`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` 被破坏(例如,由于线程中断或异常),则需要重新创建它。