CountDownLatch 是一個同步輔助類,允許一個或多個線程等待其他線程完成操作。它基於 AQS(AbstractQueuedSynchronizer)的共享鎖模式實現,計數器不可重置,適合「一等多」場景。
| 特性 | CountDownLatch | CyclicBarrier |
|---|---|---|
| 核心作用 | 1或N個線程等待其他線程完成 | N個線程相互等待 |
| 計數器重置 | 不可重置 | 可重置(循環使用) |
| 適用場景 | 主線程等待多個子線程初始化完成 | 多線程分階段計算,需同步進入下一階段 |
// 構造函數:初始化計數器
public CountDownLatch(int count)
// 等待計數器歸零(可中斷)
public void await() throws InterruptedException
// 帶超時等待
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
// 計數器遞減
public void countDown()
// 獲取當前計數
public long getCount()

public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync(int count) {
setState(count); // AQS state 即為計數器
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// AQS 獲取共享鎖邏輯
public final void acquireSharedInterruptibly(long arg) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg);
}
// CountDownLatch 重寫:state==0 才能獲取鎖
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
當計數器 > 0 時,線程進入 CLH 隊列阻塞;計數器歸零時,所有等待線程被喚醒。
public void countDown() {
sync.releaseShared(1);
}
// AQS 釋放共享鎖
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
// CAS 遞減 state,歸零時返回 true 觸發喚醒
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0) return false;
int nextc = c - 1;
if (compareAndSetState(c, nextc)) return nextc == 0;
}
}
public class CountDownLatchDemo {
private static final int LATCH_SIZE = 5;
private static CountDownLatch doneSignal;
public static void main(String[] args) throws InterruptedException {
doneSignal = new CountDownLatch(LATCH_SIZE);
// 啟動 5 個工作線程
for (int i = 0; i < LATCH_SIZE; i++) {
new WorkerThread().start();
}
System.out.println("主線程等待開始...");
doneSignal.await(); // 阻塞直到計數器歸零
System.out.println("主線程等待結束,繼續執行...");
}
static class WorkerThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(1000); // 模擬業務處理
System.out.println(Thread.currentThread().getName() + " 完成任務");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
doneSignal.countDown(); // 計數器 -1
}
}
}
}
主線程等待開始...
Thread-0 完成任務
Thread-2 完成任務
Thread-1 完成任務
Thread-4 完成任務
Thread-3 完成任務
主線程等待結束,繼續執行...
5 個子線程並發執行,各自調用 countDown() 將計數器從 5 遞減至 0,主線程 await() 返回繼續執行。這是典型的「主線程等待多線程初始化完成」場景。