【Java 并发编程】CountDownLatch 使用场景示例
文章目錄
- I CountDownLatch 使用場景舉例
- II CountDownLatch 簡單線程阻塞示例
- III CountDownLatch 多個線程聯合阻塞示例
I CountDownLatch 使用場景舉例
1. 單個阻塞等待單個線程 : 初始化 CountDownLatch 時 , 設置其計數為 1 , 在線程 A 中調用 await() 阻塞 , 然后在線程 B 中執行操作 , 之后調用 countDown() 方法 , 計數 - 1 , 線程 A 阻塞解除 ;
2. 單個阻塞等待多個線程 : 初始化 CountDownLatch 時 , 設置其計數為 2 , 在線程 A 中調用 await() 阻塞 ; 然后在線程 B 中執行操作 , 調用 countDown() 方法 , 計數 - 1 ; 同時在線程 C 中執行更長時間的操作 , 調用 countDown() 方法 , 計數 - 1 ; 線程 B 和 C 的操作執行完畢后 , 其計數才減為 0 , 此時線程 A 中的阻塞解除 ;
3. 多個線程阻塞等待單個線程 : 多個線程中調用 CountDownLatch 對象 await() 方法阻塞 , 在另外一個線程中將計數 countDown() 為 0 , 這些線程即可執行 ;
4. 多個線程阻塞等待多個線程 : 多個線程中調用 CountDownLatch 對象 await() 方法阻塞 , 在另外多個線程中將計數 countDown() 為 0 , 被阻塞這些線程即可執行 ;
5. CountDownLatch 使用場景 :
- ① 單線程等待單線程 : 線程 A 阻塞 , 等待線程 B 執行完畢后 , 在執行線程 A 操作 ;
- ② 單線程等待多線程 : 線程 A 阻塞 , 等待線程 B , C , D 等線程執行完畢 , 在執行線程 A 操作 ;
- ③ 單線程與多線程互相阻塞 : 線程 B , C , D , 先被 new CountDownLatch ( 1 ) 對象阻塞住 , 在線程 A 中先解除 B , C , D 的阻塞 , 然后 B , C , D 這三個線程才能繼續執行 , 線程 A 解除之后 , 馬上被 new CountDownLatch ( 3 ) 對象阻塞 , B , C , D 三個線程執行完后 , 每個線程計數減一 , 之后解除線程 A 阻塞 , 繼續執行線程 A 的內容 ;
- ④ 單線程與多線程互相阻塞并設置超時時間 : 在上述 ③ 情況的基礎上 , 加上超時等待 , 如果 B , C , D 線程在指定時間內沒有執行完畢 , 那么線程 A 也解除阻塞 , 繼續向下執行之后的代碼 ;
II CountDownLatch 簡單線程阻塞示例
1. 代碼說明 : 子線程運行后調用 CountDownLatch 的 await 方法阻塞 , 在主線程中調用 countDown 方法將計數減為 0 , 子線程解除阻塞 ;
2. 代碼示例 :
import java.util.concurrent.CountDownLatch;/*** 子線程運行后調用 CountDownLatch 的 await 方法阻塞 ,* 在主線程中調用 countDown 方法將計數減為 0 , 子線程解除阻塞*/ public class CountDownLatchDemo {public static void main(String[] args) {System.out.println("1. 主線程 : 開始運行 , 創建 CountDownLatch 對象初始計數為 1");//創建 CountDownLatch 對象 , 初始計數為 1CountDownLatch countDownLatch = new CountDownLatch(1);System.out.println("2. 主線程 : 創建子線程并運行");//創建子線程 , 并設置其 countDownLatch 對象, 運行子線程MyThread myThread = new MyThread(countDownLatch);myThread.start();System.out.println("3. 主線程 : 調用 countDownLatch.countDown() 方法");countDownLatch.countDown();System.out.println("4. 主線程 : 運行結束");}static class MyThread extends Thread{/*** 用于阻塞的 CountDownLatch 對象*/CountDownLatch countDownLatch;/*** 主線程中傳入 CountDownLatch 對象 , 兩個線程公用一個該對象* @param countDownLatch*/public MyThread(CountDownLatch countDownLatch) {this.countDownLatch = countDownLatch;}@Overridepublic void run() {super.run();try {System.out.println("1. 子線程 : 開始運行 , 并調用 countDownLatch.await() 方法阻塞");//阻塞子線程countDownLatch.await();System.out.println("2. 子線程 : CountDownLatch 對象計數為 0 , 子線程繼續運行并結束");} catch (InterruptedException e) {e.printStackTrace();}}}}3. 執行結果 :
1. 主線程 : 開始運行 , 創建 CountDownLatch 對象初始計數為 1 2. 主線程 : 創建子線程并運行 3. 主線程 : 調用 countDownLatch.countDown() 方法 1. 子線程 : 開始運行 , 并調用 countDownLatch.await() 方法阻塞 4. 主線程 : 運行結束 2. 子線程 : CountDownLatch 對象計數為 0 , 子線程繼續運行并結束III CountDownLatch 多個線程聯合阻塞示例
1. 情景描述 : 運動員賽跑 , 1 個裁判 , 4 個運動員 , 4 個運動員首先等待裁判發令 , 才能開始跑 , 裁判發令后在終點等待 4 個運動員都達到終點后 , 在宣布成績 ;
2. 線程模型分析 :
- ① 線程 : 裁判員是一個單獨的線程 , 4 個運動員是 4 個獨立的線程 ;
- ② CountDownLatch : 兩種 CountDownLatch 對象 , 一個用于阻塞裁判員線程 , 一個用于阻塞運動員線程 ;
- ③ 運動員線程 : 四個運動員線程一開始運行后 , 馬上調用 new CountDownLatch(1) 對象阻塞住 , 不能向后運行 ;
- ④ 裁判員線程 : 裁判員線程要等四個運動員線程啟動后才能執行 , 先調用 countDown 將四個運動員線程取消阻塞 , 然后調用new CountDownLatch(4) 對象 的 await 阻塞 , 每個運動員線程跑到終點后 , 調用 countDown 方法 , 四個運動員全部到達終點后 , 裁判員解除阻塞 , 宣布成績 ;
3. 代碼示例 :
import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** 情景描述 : 運動員賽跑 , 1 個裁判 , 4 個運動員 ,* 4 個運動員首先等待裁判發令 , 才能開始跑 ,* 裁判發令后在終點等待 4 個運動員都達到終點后 , 在宣布成績 ;** 線程模型分析 :** ① 線程 : 裁判員是一個單獨的線程 , 4 個運動員是 4 個獨立的線程 ;* ② CountDownLatch : 兩種 CountDownLatch 對象 , 一個用于阻塞裁判員線程 , 一個用于阻塞運動員線程 ;* ③ 運動員線程 ( 子線程 ) : 四個運動員線程一開始運行后 , 馬上調用 new CountDownLatch(1) 對象阻塞住 , 不能向后運行 ;* ④ 裁判員線程 ( 主線程 ) : 裁判員線程要等四個運動員線程啟動后才能執行 , 先調用 countDown 將四個運動員線程取消阻塞 ,* 然后調用new CountDownLatch(4) 對象 的 await 阻塞 , 每個運動員線程跑到終點后 ,* 調用 countDown 方法 , 四個運動員全部到達終點后 , 裁判員解除阻塞 , 宣布成績 ;*/ public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//用于存儲四個運動員的成績int[] grades = new int[4];//四個運動員線程的線程池ExecutorService executorService = Executors.newCachedThreadPool();//阻塞運動員線程的倒計時鎖對象 , 需要裁判員線程解鎖CountDownLatch runnerLatch = new CountDownLatch(1);//阻塞裁判線程的倒計時鎖對象 , 需要四個運動員線程解鎖CountDownLatch judgeLatch = new CountDownLatch(4);//創建并執行運動員線程 , 使用線程池機制執行for(int i = 0; i < 4; i ++){int finalI = i;//創建運動員線程Runnable runnable = new Runnable() {@Overridepublic void run() {try {System.out.println( finalI + " 號運動員準備完畢 , 等待裁判員發令");runnerLatch.await();System.out.println( finalI + " 號運動員起跑");//設置運動員成績 , 這里用一個隨機數代替grades[finalI] = (int) (Math.random() * 10000);Thread.sleep(grades[finalI]);//通知裁判員到達終點judgeLatch.countDown();System.out.println( finalI + " 號運動員到達終點");} catch (InterruptedException e) {e.printStackTrace();}}};//使用線程池調度運行該線程executorService.execute(runnable);}System.out.println("裁判員 : 發令 , 起跑");//裁判員線程在運動員準備完畢后 , 解除上述 4 個運動員線程的阻塞 , 即運動員起跑runnerLatch.countDown();System.out.println("裁判員 : 在終點等待 4 名運動員");//裁判員線程阻塞, 等待 4 個運動員線程執行完畢judgeLatch.await();System.out.println("裁判員 : 運動員全部到達終點成績為 0 號 : " + grades[0] +" , 1 號 : " + grades[1] +" , 2 號 : " + grades[2] +" , 3 號 : " + grades[3]);}}4. 執行結果 :
裁判員 : 發令 , 起跑 裁判員 : 在終點等待 4 名運動員 2 號運動員準備完畢 , 等待裁判員發令 2 號運動員起跑 1 號運動員準備完畢 , 等待裁判員發令 1 號運動員起跑 0 號運動員準備完畢 , 等待裁判員發令 0 號運動員起跑 3 號運動員準備完畢 , 等待裁判員發令 3 號運動員起跑 1 號運動員到達終點 2 號運動員到達終點 0 號運動員到達終點 3 號運動員到達終點 裁判員 : 運動員全部到達終點成績為 0 號 : 5601 , 1 號 : 1763 , 2 號 : 4700 , 3 號 : 9650總結
以上是生活随笔為你收集整理的【Java 并发编程】CountDownLatch 使用场景示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 并发编程】CountDown
- 下一篇: 【Java 网络编程】NIO Buffe