CyclicBarrier (可重複使用的屏障) 讓一組執行緒在達到「集合點」前相互等待,全員到齊後**同時釋放**繼續執行,並可選擇性執行「屏障動作」。適用於多階段並行任務同步(如 MapReduce 分階段、遊戲關卡載入、並行計算合併結果)。
| 特性 | CyclicBarrier | CountDownLatch |
|---|---|---|
| 計數方向 | 計數**遞增** (await 呼叫次數) | 計數**遞減** (countDown) |
| 可重用 | ✅ reset() 重置 | ❌ 一次性 |
| 屏障動作 | ✅ 建構子傳入 Runnable | ❌ |
| 典型場景 | 反覆同步點、多階段流水線 | 啟動等待、一次性聚合 |
import java.util.Random;
import java.util.concurrent.*;
public class CyclicBarrierDemo {
// 模擬元件:產生隨機數 → 等待屏障 → 合併相鄰結果
static class ComponentTask implements Runnable {
private final CyclicBarrier barrier;
private final int id;
private final int[] sharedArray;
ComponentTask(CyclicBarrier barrier, int[] array, int id) {
this.barrier = barrier; this.id = id; this.sharedArray = array;
}
@Override public void run() {
try {
// 階段 1:各自產生資料
sharedArray[id] = new Random().nextInt(100);
System.out.printf("Component %d 生成: %d%n", id, sharedArray[id]);
// 到達屏障等待
System.out.printf("Component %d 等待屏障...%n", id);
barrier.await(); // 可能拋 InterruptedException / BrokenBarrierException
System.out.printf("Component %d 釋放繼續...%n", id);
// 階段 2:合併自己與下一個元件的值
int result = sharedArray[id] + sharedArray[id + 1];
System.out.printf("Component %d 合併結果: %d%n", id, result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final int[] data = new int[3]; // 0,1 為元件資料,2 為屏障動作寫入總和
// 建構子:parties=2 (兩個元件), barrierAction=屏障動作
CyclicBarrier barrier = new CyclicBarrier(2, () -> {
System.out.println(">>> 屏障動作執行:計算總和存入 data[2]");
data[2] = data[0] + data[1];
});
new Thread(new ComponentTask(barrier, data, 0)).start();
new Thread(new ComponentTask(barrier, data, 1)).start();
}
}
Thread-0 (id=0) Thread-1 (id=1) Barrier Action
| | |
|-- 生成 data[0]=42 --->| |
| |-- 生成 data[1]=58 --->|
| | |
|------- await() ------>| |
| |------- await() ------>| (雙方到達)
| | |
| | |-- 執行屏障動作: data[2]=100
| | |
|<------ 釋放繼續 ------| |
| |<------ 釋放繼續 ------| (同時釋放)
| | |
|-- 合併 data[0]+data[1]-- |
| |-- 合併 data[1]+data[2]--|
await():阻塞至屏障打開,回傳當前執行緒的到達索引 (0~parties-1)。await(timeout, unit):帶超時,超時拋 TimeoutException 並打破屏障。reset():重置屏障狀態,**已等待執行緒會拋 BrokenBarrierException**。getNumberWaiting() / getParties():監控用。isBroken():屏障是否處於打破狀態 (超時/中斷/重置導致)。try {
barrier.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 保留中斷狀態
// 清理資源並退出
} catch (BrokenBarrierException e) {
// 屏障已打破,本輪同步失敗,需決定重試或放棄
}
CyclicBarrier 建構後 parties 固定。若需動態增減參與者,可組合 Phaser (JDK 7+) 實現更靈活的分階段同步。