cyclicbarrier通过计数器和condition实现线程同步,所有线程调用await()后阻塞,最后一个线程将计数器减至0并唤醒全部线程,确保它们从await()返回后“同时”执行后续任务。

CyclicBarrier 通过“等待-释放”同步机制,确保所有参与线程在到达屏障点后**阻塞等待彼此**,直到指定数量的线程全部就位,才**一次性唤醒全部线程**,从而实现真正意义上的“同时进入后续任务”。
核心原理:计数器 + 条件等待
CyclicBarrier 内部维护一个可重置的计数器(parties),每有一个线程调用 await(),计数器减一。当计数器归零时,所有等待线程被唤醒;否则,调用线程被挂起在 Condition 队列中。这个过程由同一把锁(ReentrantLock)保护,保证计数和唤醒的原子性。
- 所有线程必须调用同一个 CyclicBarrier 实例的
await() - 任意线程调用
await()后,会立即阻塞,不继续执行后续代码 - 最后一个到达的线程负责触发唤醒——它把计数器减到 0,然后调用
Condition.signalAll()
“同时进入”的关键保障
所谓“同时”,不是指毫秒级严格同步,而是指所有线程从 await() 返回的时刻,都处于屏障释放后的**同一逻辑起点**。JVM 和操作系统调度可能带来微小时间差,但语义上它们已脱离屏障、开始执行后续任务。
- 所有线程从
await()返回后,才开始执行 barrier 后的代码 - 可选的
Runnable回调(barrier action)由最后一个到达的线程在唤醒他人前执行,常用于初始化或汇总操作 - 即使某个线程提前完成前置任务,也必须等待其他线程,不会“抢先”执行后续逻辑
注意边界情况
实际使用中,“同时性”依赖正确使用模式,以下情况会破坏预期行为:
- 线程未全部调用
await()(如异常退出、提前 return),导致计数器无法归零,其余线程永久阻塞 - 多个线程共用同一个 CyclicBarrier,但部分线程重复调用
await()(例如在循环中误用),造成计数错乱 - 未处理
BrokenBarrierException或InterruptedException,导致异常线程退出后屏障被破坏,其余线程收到异常而非正常释放
简单示例:三线程协同启动
三个线程各自准备数据,全部就绪后一起计算:
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程已就位,开始计算")); // 每个线程执行: prepareData(); barrier.await(); // 卡在这里,直到第三个人到达 doComputation(); // 所有线程几乎同时执行这行Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











