`CyclicBarrier` 是 Java 中的一個同步輔助工具類,它允許一組線程相互等待,直到所有線程都達到了某個公共屏障點(barrier point)。當所有線程都到達屏障點時,它們可以繼續執行后續操作。`CyclicBarrier` 的特點是可以重復使用,即當一組線程都到達屏障點并釋放后,可以再次使用同一個 `CyclicBarrier` 對象來等待下一組線程。
### 場景描述
假設我們有一個任務,需要多個線程共同完成,這些線程各自執行一部分工作,但必須在所有線程都完成自己的部分工作后,才能一起執行下一步。例如,一個團隊需要完成多個獨立的數據分析任務,但最終的報告需要在所有數據都分析完成后才能生成。
### 步驟
1. **初始化 CyclicBarrier**:
? ?創建一個 `CyclicBarrier` 對象,并設置一個參數,表示需要等待的線程數量。
? ?```java
? ?int numberOfThreads = 5; // 假設有5個線程
? ?CyclicBarrier barrier = new CyclicBarrier(numberOfThreads);
? ?```
2. **創建并啟動線程**:
? ?為每個任務創建一個線程,這些線程將執行各自的任務。
? ?```java
? ?for (int i = 0; i < numberOfThreads; i++) {
? ? ? ?new Thread(new TaskRunner(i, barrier)).start();
? ?}
? ?```
3. **定義任務**:
? ?實現 `TaskRunner` 線程任務,用于執行特定的任務,并在完成后等待其他線程。
? ?```java
? ?class TaskRunner implements Runnable {
? ? ? ?private final int taskNumber;
? ? ? ?private final CyclicBarrier barrier;
? ? ? ?public TaskRunner(int taskNumber, CyclicBarrier barrier) {
? ? ? ? ? ?this.taskNumber = taskNumber;
? ? ? ? ? ?this.barrier = barrier;
? ? ? ?}
? ? ? ?@Override
? ? ? ?public void run() {
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?System.out.println("Task " + taskNumber + " is running.");
? ? ? ? ? ? ? ?// 執行任務
? ? ? ? ? ? ? ?// 模擬任務執行時間
? ? ? ? ? ? ? ?Thread.sleep((long) (Math.random() * 1000));
? ? ? ? ? ? ? ?System.out.println("Task " + taskNumber + " is completed.");
? ? ? ? ? ? ? ?// 等待其他線程完成
? ? ? ? ? ? ? ?barrier.await();
? ? ? ? ? ? ? ?// 所有線程都到達屏障點后執行的代碼
? ? ? ? ? ? ? ?System.out.println("All tasks completed, proceeding to next step for task " + taskNumber);
? ? ? ? ? ?} catch (InterruptedException | BrokenBarrierException e) {
? ? ? ? ? ? ? ?Thread.currentThread().interrupt();
? ? ? ? ? ? ? ?System.out.println("Task " + taskNumber + " was interrupted or barrier was broken.");
? ? ? ? ? ?}
? ? ? ?}
? ?}
? ?```
4. **等待所有線程完成**:
? ?每個線程在完成自己的任務后調用 `barrier.await()` 方法,這將導致它們在屏障點等待,直到所有線程都到達該點。
5. **執行后續操作**:
? ?一旦所有線程都到達屏障點,`barrier.await()` 方法將返回,所有線程將同時繼續執行后續操作。
### 分析
在這個案例中,`CyclicBarrier` 用于同步多個線程,確保它們在繼續執行下一步之前都完成了自己的任務。每個線程在完成自己的任務后會等待其他線程,直到所有線程都到達屏障點。這保證了所有任務的協調完成。
使用 `CyclicBarrier` 的優點是它可以重復使用,這意味著一旦當前的屏障點被釋放,可以立即重置 `CyclicBarrier` 的計數器,以便在下一次使用。這使得 `CyclicBarrier` 成為處理需要重復同步的循環任務的理想選擇。
需要注意的是,`barrier.await()` 方法可能會拋出 `InterruptedException` 和 `BrokenBarrierException` 異常,因此需要適當處理這些異常。此外,如果 `CyclicBarrier` 被破壞(例如,由于線程中斷或異常),則需要重新創建它。
?