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

Java 併發工具 CyclicBarrier 詳細實戰範例 (多線程同步屏障)

     編輯:Java 相關知識

CyclicBarrier (可重複使用的屏障) 讓一組執行緒在達到「集合點」前相互等待,全員到齊後**同時釋放**繼續執行,並可選擇性執行「屏障動作」。適用於多階段並行任務同步(如 MapReduce 分階段、遊戲關卡載入、並行計算合併結果)。

核心特性對比

特性CyclicBarrierCountDownLatch
計數方向計數**遞增** (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]--|

關鍵 API

  • 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) {
    // 屏障已打破,本輪同步失敗,需決定重試或放棄
}

進階應用:動態調整 parties

CyclicBarrier 建構後 parties 固定。若需動態增減參與者,可組合 Phaser (JDK 7+) 實現更靈活的分階段同步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved