首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 5 大同步輔助類深度解析:Semaphore、CountDownLatch、CyclicBarrier、Phaser、Exchanger

     編輯:Java 相關知識

為什麼需要同步輔助類?

synchronized、wait/notify 是底層原語,寫複雜協作邏輯易出錯、難維護。JDK 5+ 在 java.util.concurrent 提供 5 種高層同步工具,封裝常見協作模式,提升可讀性與正確性。

1. Semaphore(信號量)— 控制並發存取數

核心概念:維護一組「許可證」,線程 acquire() 取得許可、release() 歸還。許可數 = 允許同時存取的線程數。

// 僅允許 3 個線程同時進入關鍵區
Semaphore sem = new Semaphore(3);

sem.acquire();
try {
    // 存取共享資源(資料庫連線池、檔案句柄、硬體裝置)
} finally {
    sem.release();
}
  • 公平/非公平:建構子 new Semaphore(3, true) 開啟公平模式(FIFO)。
  • 應用場景:資源池限流、限制並發 API 呼叫、實現有界容器。

2. CountDownLatch(倒數閂)— 一次性等待多任務完成

核心概念:計數器初始化為 N,每個任務完成 countDown(),主線程 await() 阻塞直到歸零。不可重置。

CountDownLatch latch = new CountDownLatch(3); // 3 個子任務

// 子任務
new Thread(() -> { doWork(); latch.countDown(); }).start();
// ... 啟動 3 個

latch.await(); // 主線程阻塞,直到 3 個都完成
System.out.println("全部完成");
  • 應用場景:服務啟動等待多組件初始化、並行計算聚合結果、測試同步點。

3. CyclicBarrier(循環柵欄)— 固定團隊互相等待

核心概念: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();
}
  • 應用場景:並行迭代計算(MapReduce 風格)、多階段遊戲回合同步、批次處理階段切分。

4. Phaser(階段器)— 靈活的多階段同步

核心概念:結合 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) 等待特定階段。
  • 應用場景:分階段管道處理、動態任務圖、Fork/Join 子任務同步。

5. Exchanger(交換器)— 雙線程資料交換

核心概念:兩個線程在 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 並恢復中斷狀態。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved