好程式設計師Java培訓分享Java多執行緒併發
好程式設計師Java 培訓分享 Java 多執行緒併發, 1 Java 執行緒實現 / 建立方式
繼承 Thread 類
Thread 類本質上是實現了 Runnable 介面的一個例項,代表一個執行緒的例項。啟動執行緒的唯一方法就是透過 Thread 類的 start() 例項方法。 start() 方法是一個 native 方法,它將啟動一個新執行緒,並執行 run() 方法。
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
} }
MyThread myThread1 = new MyThread();
myThread1.start();
實現 Runnable 介面
如果自己的類已經 extends 另一個類,就無法直接 extends Thread ,此時,可以實現一個 Runnable 介面。
public class MyThread extends OtherClass implements Runnable {
public void run() {
System.out.println("MyThread.run()");
} } // 啟動
MyThreadMyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
target.run()public void run() {
if (target != null) {
target.run();
} }
ExecutorService 、 Callable 、 Future 有返回值執行緒
有返回值的任務必須實現 Callable 介面,類似的,無返回值的任務必須 Runnable 介面。執行 Callable 任務後,可以獲取一個 Future 的物件,在該物件上呼叫 get 就可以獲取到 Callable 任務返回的 Object 了,再結合執行緒池介面 ExecutorService 就可以實現傳說中有返回結果的多執行緒了。
// 建立一個執行緒池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 建立多個有返回值的任務
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new MyCallable(i + " ");
// 執行任務並獲取 Future 物件
Future f = pool.submit(c); list.add(f);
} // 關閉執行緒池 pool.shutdown();
// 獲取所有併發任務的執行結果 for (Future f : list) {
// 從 Future 物件上獲取任務的返回值,並輸出到控制檯 System.out.println("res : " + f.get().toString());
}
基於執行緒池的方式
執行緒和資料庫連線這些資源都是非常寶貴的資源。如果每次需要的時候建立,不需要的時候銷燬,是非常浪費資源的。那麼我們就可以使用快取的策略,也就是使用執行緒池。
// 建立執行緒池 ExecutorService threadPool = Executors.newFixedThreadPool(10);
while(true) { threadPool.execute(new Runnable() {
// 提交多個執行緒執行 @Override public void run() {
System.out.println(Thread.currentThread().getName() + " is running ..");
try {
Thread.sleep(3000);
}
catch (InterruptedException e) {
e.printStackTrace();
} } }); }}
2 同步鎖與死鎖
同步鎖當多個執行緒同時訪問同一個資料時,很容易出現問題。為了避免這種情況出現,我們要保證執行緒同步互斥,就是指併發執行的多個執行緒,在同一時間內只允許一個執行緒訪問共享資料。Java 中可以使用 synchronized 關鍵字來取得一個物件的同步鎖。
死鎖何為死鎖,就是多個執行緒同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放。
3 執行緒池原理
執行緒池做的工作主要是控制執行的執行緒的數量,處理過程中將任務放入佇列,然後線上程建立後啟動這些任務,如果執行緒數量超過了最大數量超出數量的執行緒排隊等候,等其它執行緒執行完畢,再從佇列中取出任務來執行。主要特點為:執行緒複用; 控制最大併發數 ; 管理執行緒。
執行緒複用一個Thread 的類都有一個 start 方法。當呼叫 start 啟動執行緒時 Java 虛擬機器會呼叫該類的 run 方法。那麼該類的 run() 方法中就是呼叫了 Runnable 物件的 run() 方法。我們可以繼承重寫 Thread 類,在其 start 方法中新增不斷迴圈呼叫傳遞過來的 Runnable 物件。這就是執行緒池的實現原理。迴圈方法中不斷獲取 Runnable 是用 Queue 實現的,在獲取下一個 Runnable 之前可以是阻塞的。
執行緒池的組成一般的執行緒池主要分為以下 4 個組成部分:
(1) 執行緒池管理器:用於建立並管理執行緒池。 (2) 工作執行緒:執行緒池中的執行緒。 (3) 任務介面:每個任務必須實現的介面,用於工作執行緒排程其執行。 (4) 任務佇列:用於存放待處理的任務,提供一種緩衝機制。
Java 中的執行緒池是透過 Executor 框架實現的,該框架中用到了 Executor , Executors , ExecutorService , ThreadPoolExecutor , Callable 和 Future 、 FutureTask 這幾個類。
ThreadPoolExecutor 的構造方法如下:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}
corePoolSize :指定了執行緒池中的執行緒數量。
maximumPoolSize :指定了執行緒池中的最大執行緒數量。
keepAliveTime :當前執行緒池數量超過 corePoolSize 時,多餘的空閒執行緒的存活時間,即多次時間內會被銷燬。
unit : keepAliveTime 的單位。
workQueue :任務佇列,被提交但尚未被執行的任務。
threadFactory :執行緒工廠,用於建立執行緒,一般用預設的即可。
handler :拒絕策略,當任務太多來不及處理,如何拒絕任務。
拒絕策略執行緒池中的執行緒已經用完了,無法繼續為新任務服務,同時,等待佇列也已經排滿了,再也塞不下新任務了。這時候我們就需要拒絕策略機制合理的處理這個問題。
JDK 內建的拒絕策略如下:
AbortPolicy :直接丟擲異常,阻止系統正常執行。
CallerRunsPolicy :只要執行緒池未關閉,該策略直接在呼叫者執行緒中,執行當前被丟棄的任務。顯然這樣做不會真的丟棄任務,但是,任務提交執行緒的效能極有可能會急劇下降。
DiscardOldestPolicy :丟棄最老的一個請求,也就是即將被執行的一個任務,並嘗試再次提交當前任務。
DiscardPolicy :該策略默默地丟棄無法處理的任務,不予任何處理。如果允許任務丟失,這是最好的一種方案。
以上內建拒絕策略均實現了 RejectedExecutionHandler 介面,若以上策略仍無法滿足實際需要,完全可以自己擴充套件 RejectedExecutionHandler 介面。
Java 執行緒池工作過程 (1) 執行緒池剛建立時,裡面沒有一個執行緒。任務佇列是作為引數傳進來的。不過,就算佇列裡面有任務,執行緒池也不會馬上執行它們。
(2) 當呼叫 execute() 方法新增一個任務時,執行緒池會做如下判斷:
a) 如果正在執行的執行緒數量小於 corePoolSize ,那麼馬上建立執行緒執行這個任務 ;
b) 如果正在執行的執行緒數量大於或等於 corePoolSize ,那麼將這個任務放入佇列 ;
c) 如果這時候佇列滿了,而且正在執行的執行緒數量小 maximumPoolSize ,那麼還是要建立非核心執行緒立刻執行這個任務 ;
d) 如果佇列滿了,而且正在執行的執行緒數量大於或等 maximumPoolSize ,那麼執行緒池會丟擲異常 RejectExecutionException 。
(3) 當一個執行緒完成任務時,它會從佇列中取下一個任務來執行。
(4) 當一個執行緒無事可做,超過一定的時間 (keepAliveTime) 時,執行緒池會判斷,如果當前執行的執行緒數大於 corePoolSize ,那麼這個執行緒就被停掉。所以執行緒池的所有任務完成後,它最終會收縮到 corePoolSize 的大小。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2704333/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 好程式設計師Java培訓分享Java多執行緒程式設計師Java執行緒
- 好程式設計師Java培訓分享Java多執行緒常見面試問題程式設計師Java執行緒面試
- 好程式設計師Java培訓分享四種常用執行緒池介紹程式設計師Java執行緒
- 好程式設計師Java培訓分享Java程式設計技巧程式設計師Java
- 好程式設計師Java培訓分享Java程式設計師技能提升指南程式設計師Java
- 好程式設計師Java培訓分享SpringBoot -YAML程式設計師JavaSpring BootYAML
- 好程式設計師Java教程分享Java多執行緒常見面試題程式設計師Java執行緒面試題
- 好程式設計師Java培訓告訴你Java-執行緒怎麼來的?程式設計師Java執行緒
- Java併發程式設計:Java執行緒Java程式設計執行緒
- 好程式設計師Java學習路線分享多執行緒概念程式設計師Java執行緒
- 好程式設計師Java培訓分享如何快速入門Java程式設計程式設計師Java
- 好程式設計師Java培訓分享Java之反射技術程式設計師Java反射
- 好程式設計師Java培訓分享如何快速入門Java程式設計師Java
- 好程式設計師Java培訓分享Java包是什麼?程式設計師Java
- 好程式設計師Java培訓分享maven-概述程式設計師JavaMaven
- 好程式設計師Java培訓分享BigDecimal的用法程式設計師JavaDecimal
- 好程式設計師Java培訓分享Java程式設計師常用的工具類庫程式設計師Java
- 好程式設計師Java培訓分享20個Java程式設計師基礎題程式設計師Java
- Java 多執行緒與併發程式設計 · Java 工程師必知必會Java執行緒程式設計工程師
- 好程式設計師Java培訓分享Java EE與Java的區別程式設計師Java
- 好程式設計師Java培訓分享學Java程式設計要注意什麼程式設計師Java
- 好程式設計師Python培訓分享Python中程式和執行緒詳解程式設計師Python執行緒
- 好程式設計師Java培訓分享Java和HTML的區別?程式設計師JavaHTML
- 好程式設計師Java培訓分享Java物件導向概念解析程式設計師Java物件
- 好程式設計師Java培訓分享Java初學者必讀程式設計師Java
- 好程式設計師Java培訓分享SpringBoot -啟動流程程式設計師JavaSpring Boot
- 好程式設計師Java培訓分享For迴圈詳解程式設計師Java
- 好程式設計師Java培訓分享Spring Ioc的原理程式設計師JavaSpring
- 好程式設計師Java培訓分享SpringBoot入門篇程式設計師JavaSpring Boot
- 好程式設計師Java培訓分享本地快取如何設計程式設計師Java快取
- java併發程式設計——執行緒池Java程式設計執行緒
- java併發程式設計——執行緒同步Java程式設計執行緒
- 好程式設計師Java培訓分享Java面試題集合篇一程式設計師Java面試題
- 好程式設計師Java培訓分享Java面試題集合篇二程式設計師Java面試題
- 好程式設計師Java培訓分享學習Java需要哪些基礎程式設計師Java
- 好程式設計師Java培訓分享面試Java的注意事項程式設計師Java面試
- 好程式設計師Java培訓分享Java中級面試題合集程式設計師Java面試題
- 好程式設計師Java培訓分享Java集合的兩種排序方法程式設計師Java排序