CyclicBarrier是Java中支持多轮同步等待的可重用并发工具,通过计数器协调线程在屏障点集体阻塞与释放,并可配置屏障动作实现每轮聚合操作。

CyclicBarrier 是 Java 并发包(java.util.concurrent)中用于多线程“多轮同步等待”的核心工具,它让一组线程在某个屏障点(barrier)上互相等待,直到所有线程都到达后才同时放行——且可重复使用,因此适合需要**多轮并行执行 + 每轮同步协调**的场景。
一、CyclicBarrier 的基本原理与关键参数
它内部维护一个计数器(初始值为参与线程数),每个线程调用 await() 时计数器减一;当计数器归零,所有等待线程被唤醒并继续执行,同时计数器重置(这就是“循环”Cyclic 的由来)。构造时可选传入一个 Runnable 类型的“屏障动作”(barrier action),它会在最后到达的线程释放其他线程前执行,常用于汇总、校验或触发下一轮准备。
- 构造方式:
new CyclicBarrier(int parties)或new CyclicBarrier(int parties, Runnable barrierAction) -
await()是阻塞方法,支持超时(await(long timeout, TimeUnit unit)),超时未凑齐则抛出BrokenBarrierException - 任意线程在等待中被中断,或屏障被
reset()/broken,都会导致其他等待线程收到BrokenBarrierException
二、实现多轮并行同步的典型结构
要实现“多轮”,关键是把 CyclicBarrier 放在循环体内,每轮启动一批线程协作,共用同一个 barrier 实例。注意:线程本身可以复用(如用线程池),但每轮需确保所有参与者都调用一次 await()。
- 用固定线程池提交 N 个任务,每个任务执行“计算 → await() → 下一步”,N 等于 barrier 的 parties 数
- 每轮开始前,可检查
getNumberWaiting()确认无残留等待;必要时调用reset()清除中断状态 - 屏障动作(barrierAction)适合做该轮的聚合操作,比如将各线程结果汇总到共享容器,或打印本轮完成日志
三、一个实际的多轮计算示例
假设模拟 3 台机器并行处理一批数据,每轮处理 10 条记录,共执行 5 轮:
立即学习“Java免费学习笔记(深入)”;
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("✅ 第 " + (round.get()) + " 轮全部完成"));
AtomicInteger round = new AtomicInteger(1);
for (int r = 0; r < 5; r++) {
// 启动 3 个线程,各自处理本机数据
for (int i = 0; i < 3; i++) {
executor.submit(() -> {
int data = localProcess(); // 模拟本地计算
try {
barrier.await(); // 等待其他两台机器
} catch (Exception e) {
Thread.currentThread().interrupt();
}
if (r == 4) System.out.println("? 最终轮,启动合并逻辑");
});
}
round.incrementAndGet();
}
这里每轮 3 个线程共同等待,屏障动作标记轮次;第 5 轮结束后可统一触发汇总——逻辑清晰,无需手动管理锁或 volatile 协调。
四、对比 CountDownLatch 和 Phaser 的适用边界
CyclicBarrier 的不可替代性在于“可重置的、参与者数量固定且彼此对等”的同步模型:
- vs
CountDownLatch:后者是一次性、主从模式(常由主线程 await,子线程 countDown),不支持多轮,也不提供 barrier action - vs
Phaser:功能更强大(动态注册/注销、分层同步),但复杂度高;若只是固定人数多轮同步,CyclicBarrier 更简洁直接 - 注意:不要用它替代
synchronized或ReentrantLock——它不保护临界资源,只解决“何时一起往下走”的时序问题
不复杂但容易忽略:真正发挥多轮价值的关键,是把 barrier 的生命周期和业务轮次对齐,并确保每轮参与者行为一致、异常路径可控。


















