synchronized、wait/notify 是底層原語,寫複雜協作邏輯易出錯、難維護。JDK 5+ 在 java.util.concurrent 提供 5 種高層同步工具,封裝常見協作模式,提升可讀性與正確性。
核心概念:維護一組「許可證」,線程 acquire() 取得許可、release() 歸還。許可數 = 允許同時存取的線程數。
// 僅允許 3 個線程同時進入關鍵區
Semaphore sem = new Semaphore(3);
sem.acquire();
try {
// 存取共享資源(資料庫連線池、檔案句柄、硬體裝置)
} finally {
sem.release();
}
new Semaphore(3, true) 開啟公平模式(FIFO)。核心概念:計數器初始化為 N,每個任務完成 countDown(),主線程 await() 阻塞直到歸零。不可重置。
CountDownLatch latch = new CountDownLatch(3); // 3 個子任務
// 子任務
new Thread(() -> { doWork(); latch.countDown(); }).start();
// ... 啟動 3 個
latch.await(); // 主線程阻塞,直到 3 個都完成
System.out.println("全部完成");
核心概念:N 個線程互相等待,直到全部到達 barrier.await(),然後全部釋放繼續。可重複使用(因此稱 Cyclic)。可選「柵欄動作」在最後一個線程到達時執行。
// 4 個線程,全部到達後執行聚合動作
CyclicBarrier barrier = new CyclicBarrier(4, () -> System.out.println("本輪聚合完成"));
for (int i = 0; i < 4; i++) {
new Thread(() -> {
computePartial();
barrier.await(); // 等待夥伴
nextRound(); // 全部釋放後繼續
}).start();
}
核心概念:結合 CountDownLatch + CyclicBarrier 並強化:動態註冊/註銷參與者、階段編號、層級化。Fork/Join 框架內部大量使用。
Phaser phaser = new Phaser(1); // 主線程先註冊
for (int i = 0; i < 3; i++) {
phaser.register(); // 子任務註冊
new Thread(() -> {
phase1(); phaser.arriveAndAwaitAdvance();
phase2(); phaser.arriveAndAwaitAdvance();
phaser.arriveAndDeregister(); // 完成註銷
}).start();
}
phaser.arriveAndAwaitAdvance(); // 主線程等待階段 1
phaser.arriveAndAwaitAdvance(); // 主線程等待階段 2
phaser.arriveAndDeregister(); // 主線程註銷,Phaser 終止
arriveAndAwaitAdvance() 到達並等待下一階段、arrive() 僅到達不等待、awaitAdvance(phase) 等待特定階段。核心概念:兩個線程在 exchange() 點交換物件,雙向同步。可視為容量為 1 的 SynchronousQueue 雙向版。
Exchanger<List<Integer>> exchanger = new Exchanger<>();
// 生產者線程
List<Integer> buffer = new ArrayList<>();
while (running) {
buffer.add(produce());
if (buffer.size() == BATCH) buffer = exchanger.exchange(buffer); // 與消費者交換滿/空緩衝區
}
// 消費者線程
List<Integer> buffer = new ArrayList<>();
while (running) {
buffer = exchanger.exchange(buffer); // 取得滿緩衝區
consume(buffer);
buffer.clear(); // 歸還空緩衝區
}
| 工具 | 可重用 | 動態參與者 | 典型用途 |
|---|---|---|---|
| Semaphore | 是 | 否 | 資源池限流、並發存取控制 |
| CountDownLatch | 否 | 否 | 一次性等待 N 個任務完成 |
| CyclicBarrier | 是 | 否 | 固定團隊循環等待、多階段迭代 |
| Phaser | 是 | 是 | 動態階段同步、Fork/Join 內部 |
| Exchanger | 是 | 固定 2 方 | 雙線程資料交換、雙緩衝 |
wait/notify。CountDownLatch 不可重用,需重用請用 CyclicBarrier 或 Phaser。Phaser 分層減少爭用。await() 皆可被中斷,捕獲 InterruptedException 並恢復中斷狀態。