CyclicBarrier
是 Java 并发工具类,基于屏障点(Barrier)实现多线程协同等待。通过 await()
阻塞线程直至所有线程到达屏障,支持重置和屏障后动作。常用于分阶段任务或并行计算结果的合并。
一、核心功能
- 协同等待:多个线程互相等待,直到全部到达屏障点后继续执行。
- 可重用性:计数器可重置,支持多次任务分阶段执行。
- 屏障后动作 :所有线程到达屏障后,可触发自定义的
Runnable
任务(如合并结果)。
二、核心方法
方法 | 说明 |
---|---|
CyclicBarrier(int parties) |
构造方法,指定等待的线程数 |
CyclicBarrier(int parties, Runnable barrierAction) |
指定线程数和屏障后触发的任务 |
int await() |
阻塞当前线程,直到所有线程到达屏障 |
int await(long timeout, TimeUnit unit) |
带超时的等待,超时抛出 TimeoutException |
void reset() |
重置屏障,未到达的线程将抛出 BrokenBarrierException |
int getParties() |
获取屏障需要的线程数 |
int getNumberWaiting() |
获取当前等待的线程数 |
三、典型使用场景
- 多阶段任务
例如:分批次处理数据,每批所有线程处理完成后进入下一阶段。 - 并行计算合并
例如:多个线程分别计算部分结果,所有线程完成后汇总最终结果。 - 模拟测试
让多个线程在特定阶段同步,观察并发行为。
四、代码示例
java
public class CyclicBarrierDemo {
public static void main(String[] args) {
int threadCount = 3;
// 定义屏障后的汇总任务
Runnable mergeAction = () -> System.out.println("所有线程到达屏障,开始合并结果...");
CyclicBarrier barrier = new CyclicBarrier(threadCount, mergeAction);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
try {
System.out.println("线程计算中...");
Thread.sleep(1000);
barrier.await(); // 等待其他线程
System.out.println("线程继续执行后续任务...");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
五、注意事项
- 线程阻塞
await()
会阻塞线程,若线程池中工作线程数不足,可能导致死锁。 - 异常处理
若有线程在等待时被中断或超时,屏障将损坏(BrokenBarrierException
),需调用reset()
重置。 - 屏障动作执行
屏障后的Runnable
任务由最后到达屏障的线程执行,其他线程继续前需等待该任务完成。 - 重置风险
reset()
会立即打破当前屏障,可能导致未到达的线程抛出异常,需谨慎使用。
六、对比 CountDownLatch
特性 | CyclicBarrier |
CountDownLatch |
---|---|---|
重用性 | 支持重置,可重复使用 | 一次性 |
核心角色 | 多线程互相等待 | 主线程等待子线程或子线程等待主线程 |
触发条件 | 所有线程到达屏障点 | 计数器归零 |
附加任务 | 支持屏障后执行自定义任务 | 无 |
七、高级用法
1. 分阶段任务
java
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("阶段完成,进入下一阶段"));
// 多线程分阶段执行任务
for (int stage = 1; stage <= 3; stage++) {
new Thread(() -> {
doStageWork(stage);
barrier.await(); // 等待所有线程完成当前阶段
}).start();
}
2. 处理屏障损坏
java
try {
barrier.await();
} catch (BrokenBarrierException e) {
System.out.println("屏障已损坏,需重置或终止任务");
barrier.reset(); // 重置屏障
}
总结 :
CyclicBarrier
适用于多线程分阶段协同工作的场景,通过可重用性和屏障后任务简化复杂同步逻辑。与 CountDownLatch
不同,它强调线程间的对等协作而非单向依赖。