文章目錄
- 核心思想:火箭發射倒計時 🚀
- 最簡單易懂的代碼示例
- 代碼解析
- 運行流程分析
核心思想:火箭發射倒計時 🚀
想象一下發射火箭的場景,在按下最終的發射按鈕之前,必須有好幾個系統同時完成自檢,比如:
- 燃料系統檢查
- 引擎系統檢查
- 導航系統檢查
控制中心(主線程)必須等待這3個檢查全部報告“正常”后,才能下達“發射”指令。
CountDownLatch
就好比是這個場景中的倒計時計數器。
-
CountDownLatch latch = new CountDownLatch(3);
- 這等于在控制中心設置了一個初始值為 3 的倒計時器。意味著我們需要等待3個檢查任務完成。
-
latch.await();
(等待)- 控制中心(主線程)調用這個方法,然后就進入等待狀態。它會一直在這里被阻塞,直到倒計時器的數字變成 0。
-
latch.countDown();
(倒數)- 每個檢查系統(工作線程)在完成自己的任務后,就調用一次這個方法。
- 每調用一次,倒計時器的數字就減一。
- 當第三個檢查系統也調用了
countDown()
后,倒計時器數字變為0,await()
的等待結束,控制中心(主線程)被喚醒,繼續執行后續的發射指令。
最簡單易懂的代碼示例
下面我們就用代碼來模擬這個“火箭發射”的場景。
package CoountDownLatch;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class SimpleCountDownLatchDemo {public static void main(String[] args) throws InterruptedException {// 1. 創建一個 CountDownLatch,計數器設置為 3// 意味著我們需要等待3個任務完成final CountDownLatch latch = new CountDownLatch(3);// 創建一個線程池來管理我們的檢查任務ExecutorService executor = Executors.newFixedThreadPool(3);System.out.println("主控室:準備發射火箭,等待各系統檢查...");// 2. 分配3個檢查任務給不同的線程for (int i = 1; i <= 3; i++) {final String checkerName = "檢查員-" + i;executor.submit(() -> {try {System.out.println("--> [" + checkerName + "] 開始進行系統檢查...");// 模擬檢查耗時Thread.sleep(new Random().nextInt(2000) + 1000); // 隨機耗時1-3秒System.out.println("... [" + checkerName + "] 檢查完成,已報告!");} catch (InterruptedException e) {e.printStackTrace();} finally {// 3. 關鍵!任務完成,調用 countDown(),計數器減一latch.countDown();}});}// 4. 主線程調用 await() 進入等待// 它會一直阻塞在這里,直到 latch 的計數器變為 0System.out.println("主控室:所有檢查任務已派出,等待報告...");latch.await();// --- 當所有檢查任務都調用了 countDown() 后,主線程才會從 await() 返回,執行以下代碼 ---System.out.println("主控室:所有系統檢查完成!準備發射!");System.out.println("3... 2... 1... 火箭發射!🚀");// 關閉線程池executor.shutdown();}
}
代碼解析
new CountDownLatch(3)
: 設置了一個需要3個“報告”才能繼續的門閂。executor.submit(...)
: 我們派出了3個檢查員(線程)去并行工作。latch.countDown()
: 這是每個檢查員完成工作后必須要做的事——向控制中心報告“我搞定了”。每報告一次,倒計時就減一。latch.await()
: 這是主線程(控制中心)的等待點。它會一直卡在這里,直到收到全部3個“搞定了”的報告。
運行流程分析
- 程序啟動,
main
線程打印 “準備發射火箭…”。 - 3個檢查員線程被創建并開始并行地執行檢查(你會看到3條 “開始進行系統檢查…” 的日志)。
main
線程打印 “所有檢查任務已派出…” 后,立刻調用latch.await()
并進入阻塞等待。- 在接下來的幾秒內,你會看到檢查員們隨機地、不按順序地完成他們的工作,并打印 “檢查完成,已報告!”。每完成一個,
latch
的計數就減一。 - 當第三個檢查員也完成并調用
countDown()
后,latch
的計數變為0。 main
線程的await()
立刻被喚醒,程序繼續執行,打印出最終的 “火箭發射!🚀”。
這個模式非常適合一個主線程需要等待多個子任務全部執行完畢后再進行匯總或執行下一步的場景。
流程:
- 定義Latch數量
- 在多線程任務中每次完成就latch.countDown();
- 在主線程中調用latch.await();進入等待,它會一直阻塞在這里,直到 latch 的計數器變為 0
- 當所有檢查任務都調用了 countDown() 后,主線程才會從 await() 返回