cyclicbarrier 的屏障在最后一个线程调用 await() 时触发,该线程同步执行 barrieraction 后唤醒其余线程;屏障自动重置,适用于循环场景,需避免 barrieraction 耗时及 await() 前执行业务逻辑。

CyclicBarrier 的屏障执行时机,关键在于“所有参与线程都调用了 await()”这一瞬间——不是第一个,也不是中间某个,而是最后一个线程抵达并触发屏障释放的那一刻。
屏障触发的精确时刻
当第 parties 个线程调用 await(),计数器归零,此时屏障立即被触发。这个线程会成为“最后一个到达者”,它承担两项任务:先执行可选的 barrierAction(如果设置了),再唤醒所有等待线程。其他线程在被唤醒后,才从 await() 方法中返回,继续执行后续代码。
- 屏障动作(
barrierAction)由最后一个到达的线程同步执行,不另起线程 - 所有线程从
await()返回是几乎同时发生的,但严格来说存在微小调度延迟 - 若任一线程在等待中被中断或超时,屏障会被打破,其余线程收到
BrokenBarrierException
同步点不是代码位置,而是逻辑汇合点
很多开发者误以为 await() 出现在哪一行,屏障就“在那里”执行。实际上,它代表的是线程完成当前阶段工作的声明。比如四个线程分别处理不同数据分片,它们各自跑完自己的计算逻辑后,才调用 await()。这个调用本身不带业务含义,但它标志着“我这部分已完成”。屏障真正生效的,是这四个“已完成”信号全部到位的时刻。
- 业务逻辑必须在
await()前完成,否则会拖慢整个屏障组 - 多个
await()调用可以出现在不同方法、不同类中,只要属于同一 CyclicBarrier 实例 - 不能靠代码行号判断同步效果,而要靠线程行为是否达成“全体就绪”状态
协调执行依赖于屏障重置机制
与 CountDownLatch 不同,CyclicBarrier 在触发后自动重置,下一轮等待无需重建实例。这意味着它的协调能力天然适用于循环场景——比如每轮仿真迭代、每批数据聚合、每次秒杀请求处理。重置发生在 barrierAction 执行完毕之后、线程被唤醒之前,整个过程对使用者透明。
- 重置是原子的,不会出现部分线程进入下一轮、部分还在上一轮的情况
- 手动调用
reset()会强制清空当前等待状态,可能导致正在 await 的线程抛出异常,慎用 - 高并发下重复使用同一个 CyclicBarrier 实例,比频繁创建 CountDownLatch 更轻量、GC 友好
常见误区与规避方式
实际使用中,容易混淆屏障的“等待结束”和“执行开始”。例如,在性能压测中用 CyclicBarrier 让 100 个线程同时发请求,有人把 HTTP 调用写在 await() 之后——这没错;但如果把请求放在 await() 之前,就失去了“同时出发”的意义。
- 屏障作用是“齐步走”,不是“排队走”:所有线程必须在同阶段完成后才集体推进
- 避免在
barrierAction中做耗时操作,否则会阻塞所有线程继续执行 - 注意线程池大小匹配
parties数量,否则可能出现线程不足导致死等











