在Java多线程编程中,线程之间的协调与同步是确保程序正确性和性能的关键。`CyclicBarrier` 是 Java 并发包 `java.util.concurrent` 中提供的一种同步工具类,它允许一组线程互相等待,直到所有线程都到达某个共同的屏障点后,才会继续执行。相比 `CountDownLatch`,`CyclicBarrier` 更适合用于多个线程需要反复协作的场景。
一、CyclicBarrier 的基本概念
`CyclicBarrier` 的中文名称为“循环屏障”,它的核心功能是让一组线程在达到某个条件之前一直阻塞,直到所有线程都到达该条件后,才一起继续运行。这种机制非常适合用于需要多个线程协同完成任务的场景,例如并行计算中的分阶段处理。
与 `CountDownLatch` 不同的是,`CyclicBarrier` 可以被重复使用(即“循环”),而 `CountDownLatch` 一旦计数归零,就不能再重置或复用。
二、CyclicBarrier 的构造方法
`CyclicBarrier` 提供了以下几种构造方法:
```java
public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
```
- parties:表示需要等待的线程数量。
- barrierAction:当所有线程到达屏障点时,会自动执行的一个任务(可以理解为一个回调函数)。
三、CyclicBarrier 的常用方法
| 方法 | 说明 |
|------|------|
| `await()` | 线程调用此方法后,会阻塞直到所有线程都到达屏障点。 |
| `getNumberWaiting()` | 返回当前正在等待的线程数。 |
| `getParties()` | 返回需要等待的线程总数。 |
| `isBroken()` | 判断屏障是否处于损坏状态。 |
| `reset()` | 将屏障重置为初始状态,可用于重复使用。 |
四、CyclicBarrier 的使用示例
下面是一个简单的例子,演示了三个线程如何通过 `CyclicBarrier` 协作:
```java
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
static class Task implements Runnable {
private CyclicBarrier barrier;
public Task(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 正在执行任务...");
Thread.sleep((long) (Math.random() 1000));
System.out.println(Thread.currentThread().getName() + " 到达屏障点");
barrier.await(); // 等待其他线程到达
System.out.println(Thread.currentThread().getName() + " 继续执行后续操作");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程已到达屏障点,开始下一步操作!");
});
for (int i = 0; i < 3; i++) {
new Thread(new Task(barrier), "Thread-" + i).start();
}
}
}
```
在这个例子中,三个线程分别执行任务,并在到达屏障点后等待其他线程。当所有线程都到达后,屏障释放,所有线程继续执行后续逻辑。
五、CyclicBarrier 的典型应用场景
1. 并行计算中的分阶段处理
在分布式计算或并行算法中,多个线程可能需要先完成各自的任务,然后统一进行下一步处理。此时可以用 `CyclicBarrier` 来同步各线程的进度。
2. 模拟多用户并发测试
在测试系统性能时,可以创建多个线程模拟用户请求,并通过 `CyclicBarrier` 控制它们同时启动或结束。
3. 数据聚合与汇总
在数据处理过程中,多个线程可能负责处理不同的子任务,最后需要将结果合并。这时可以通过 `CyclicBarrier` 来确保所有子任务完成后才进行汇总。
六、CyclicBarrier 与 CountDownLatch 的区别
| 特性 | CyclicBarrier | CountDownLatch |
|------|---------------|----------------|
| 是否可重用 | ✅ 可以 | ❌ 不可 |
| 等待方式 | 所有线程到达 | 一次性的计数减少 |
| 使用场景 | 多次协作 | 一次性事件触发 |
| 主动通知 | 由所有线程触发 | 由主线程触发 |
七、注意事项与常见问题
- 避免死锁:如果某个线程在 `await()` 调用前发生异常或被中断,可能导致其他线程无法继续执行。因此,应合理处理异常。
- 屏障损坏:如果在 `await()` 过程中发生异常,屏障可能会进入“损坏”状态,此时需调用 `reset()` 恢复。
- 线程安全:`CyclicBarrier` 是线程安全的,但使用时仍需注意共享资源的访问控制。
八、总结
`CyclicBarrier` 是 Java 并发编程中非常实用的同步工具,尤其适用于需要多个线程反复协作的场景。它不仅提供了灵活的屏障机制,还支持重复使用和自定义动作,使得线程间的协调更加高效和可控。掌握其使用方式,能够帮助开发者更好地设计高并发、高性能的应用程序。
如需进一步了解 Java 并发工具类,可以对比学习 `Semaphore`、`Exchanger` 和 `Phaser` 等相关类,以构建更复杂的并发模型。