CountDownLatch 是 Java 併發包(java.util.concurrent)中一個極具實用價值的同步輔助類,其工作原理類似「倒計時計數器」:初始化時設定計數值,呼叫 await() 的線程會阻塞等待,每呼叫一次 countDown() 計數減一,當計數歸零時,所有等待線程被同時喚醒繼續執行。
| 方法 | 說明 |
|---|---|
CountDownLatch(int count) | 構造函數,設定初始計數值 |
void countDown() | 計數器減一,若歸零則喚醒所有等待線程 |
void await() | 阻塞當前線程,直到計數歸零或被中斷 |
boolean await(long timeout, TimeUnit unit) | 帶超時的等待,超時返回 false |
long getCount() | 獲取當前計數值 |
以下完整範例模擬 5 位運動員等待發令槍響同時起跑,主線程等待所有運動員到達終點:
package basic;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCountDown {
private static final int PLAYER_AMOUNT = 5;
public static void main(String[] args) {
// 發令槍:計數為 1,所有選手 await() 等待
CountDownLatch begin = new CountDownLatch(1);
// 終點線:計數為 5,每位選手完成 countDown(),主線程 await()
CountDownLatch end = new CountDownLatch(PLAYER_AMOUNT);
Player[] players = new Player[PLAYER_AMOUNT];
for (int i = 0; i < PLAYER_AMOUNT; i++) {
players[i] = new Player(i + 1, begin, end);
}
ExecutorService executorService = Executors.newFixedThreadPool(PLAYER_AMOUNT);
for (Player player : players) {
executorService.execute(player);
}
System.out.println("比賽即將開始...");
// 發令槍響:計數歸零,喚醒所有選手
begin.countDown();
try {
// 主線程等待所有選手到達終點
end.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("比賽結束!");
}
executorService.shutdown();
}
}
class Player implements Runnable {
private final int id;
private final CountDownLatch begin;
private final CountDownLatch end;
public Player(int id, CountDownLatch begin, CountDownLatch end) {
this.id = id;
this.begin = begin;
this.end = end;
}
@Override
public void run() {
try {
// 等待發令槍
begin.await();
// 模擬跑步時間
Thread.sleep((long) (Math.random() * 100));
System.out.println("選手 " + id + " 到達終點。");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 到達終點,計數減一
end.countDown();
}
}
}
begin=1(發令槍),end=5(終點)begin.await()begin.countDown():計數歸零,5 位選手同時被喚醒開始跑步finally 區塊呼叫 end.countDown()end.await(),直到計數歸零(5→0)被喚醒,打印「比賽結束」await() 內部委託給同步器(Sync 繼承 AbstractQueuedSynchronizer)的 acquireSharedInterruptibly(1):
countDown() 呼叫 releaseShared(1))或線程中斷InterruptedException 並清除中斷狀態這種基於 AQS 共享模式的實現,保證了高效、可中斷的同步語義。
CyclicBarrier)countDown() 不會拋異常但計數停在 0,邏輯上應避免countDown() 建議放在 finally 區塊,確保計數必遞減Thread.join(),提供更靈活的控制粒度