多執行緒中CountDownLatch的含義以及和join的區別
任何執行緒,通常是應用程式的主執行緒,呼叫CountDownLatch.await()
將等到計數達到零或被另一個執行緒中斷。所有其他執行緒都需要CountDownLatch.countDown()
在完成或準備好後通過呼叫來倒計時。
一旦計數達到零,等待執行緒就會繼續。其中一個缺點/優點CountDownLatch
是它不可重複使用:一旦計數達到零,就不能再使用CountDownLatch
了。
使用CountDownLatch
當一個執行緒(比如主執行緒),需要等待一個或多個執行緒來完成,才能繼續處理。
CountDownLatch
Java 中使用的典型示例是伺服器端核心Java應用程式,它使用服務體系結構,其中多個服務由多個執行緒提供,並且應用程式無法在所有服務成功啟動之前開始處理。
package CountDownLatch_6; import java.util.concurrent.CountDownLatch; public class Manager { public static void main(String[] args) throws InterruptedException { CountDownLatch latch=new CountDownLatch(2); MyDevTeam devTeam=new MyDevTeam(latch, "dev1"); MyDevTeam devTeam2=new MyDevTeam(latch, "dev2"); devTeam.start(); devTeam2.start(); latch.await(); MyQATeam qa=new MyQATeam(); qa.start(); } } class MyDevTeam extends Thread{ CountDownLatch latch; public MyDevTeam(CountDownLatch latch,String name ) { // TODO Auto-generated constructor stub super(name); this.latch=latch; } public void run(){ System.out.println("任務分配給"+currentThread().getName()); try { Thread.sleep(2000); System.out.println(currentThread().getName()+"開始執行"); latch.countDown(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("任務已經被"+currentThread().getName()+"執行完畢"); } } class MyQATeam extends Thread{ public void run(){ System.out.println("任務分配給qa執行"); System.out.println("qa完成該任務"); } }
執行結果:
任務分配給dev2 任務分配給dev1 dev2開始執行 任務已經被dev2執行完畢 dev1開始執行 任務已經被dev1執行完畢 任務分配給qa執行 qa完成該任務
JOIN的限制: 以上示例也可以通過JOIN實現,但JOIN不能在兩種情況下使用:
- 當我們使用ExecutorService而不是Thread類來建立執行緒時。
- 修改以上示例,管理員希望在開發完成80%任務後立即將程式碼切換到QA團隊。這意味著CountDownLatch允許我們修改可用於等待另一個執行緒進行部分執行的實現。
上述程式碼修改
public void run(){ System.out.println("任務分配給"+currentThread().getName()); try { Thread.sleep(2000); System.out.println(currentThread().getName()+"第一階段任務完成"); latch.countDown(); Thread.sleep(2000); System.out.println(currentThread().getName()+"第二階段任務完成"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("任務已經被"+currentThread().getName()+"執行完畢"); } }
執行結果:
任務分配給dev1 任務分配給dev2 dev2第一階段任務完成 dev1第一階段任務完成 任務分配給qa執行 qa完成該任務 dev1第二階段任務完成 任務已經被dev1執行完畢 dev2第二階段任務完成 任務已經被dev2執行完畢
由執行結果可知qa在第二階段任務執行之前就已經執行,
這種場景下,用join是沒法實現的。
總結:呼叫join方法需要等待thread執行完畢才能繼續向下執行,而CountDownLatch只需要檢查計數器的值為零就可以繼續向下執行,相比之下,CountDownLatch更加靈活一些,可以實現一些更加複雜的業務場景。