cyclicbarrier 的 barrier action 由最后一个调用 await() 的线程在所有线程到达后、释放前执行一次,用于安全合并各线程结果;需避免耗时操作、不可再调 await(),且应确保写入完成后再 await。

CyclicBarrier 的构造函数支持传入一个 Runnable 类型的 barrier action(屏障动作),它会在最后一个线程到达屏障点、所有线程被释放前**自动执行一次**。这个机制非常适合在多阶段并行计算中,对各线程的局部结果做统一合并、统计或校验。
屏障动作的触发时机与作用范围
Barrier action 不属于任何具体线程,但它由**最后一个调用 await() 的线程执行**(即“撞上”屏障的那个线程)。此时其他线程处于阻塞等待状态,尚未被唤醒——因此你可以在 barrier action 中安全地访问、聚合所有线程已写入共享结构的结果,无需额外同步(前提是写入操作本身是线程安全的或已完成)。
注意:该动作只执行一次/每轮,且仅当所有线程都成功到达才触发;若有线程被中断或超时,action 不会执行,屏障被打破。
典型用法:用共享容器收集结果并合并
假设你启动 4 个线程分别计算某批数据的子集,并将结果存入一个线程安全的 ConcurrentHashMap 或预分配的 AtomicReferenceArray。屏障动作负责读取全部子结果,合并为最终值:
- 定义一个外部容器(如
List<integer> partialResults = Collections.synchronizedList(new ArrayList())</integer>)供各线程写入 - 构造 CyclicBarrier 时传入 barrier action:
new CyclicBarrier(4, () -> {<br> int sum = partialResults.stream().mapToInt(Integer::intValue).sum();<br> System.out.println("本轮合并结果:" + sum);<br>}); - 每个线程完成本地计算后,把结果 add 进
partialResults,再调用barrier.await()
进阶技巧:复用 barrier 并维护阶段性状态
CyclicBarrier 可重用,适合多轮迭代场景(如模拟多轮训练、分批次处理)。若需在每轮合并后清空或重置中间结果,直接在 barrier action 末尾操作即可:
- 在 action 中调用
partialResults.clear(),为下一轮准备 - 使用
AtomicInteger roundCounter记录当前轮次,在 action 中打印或存档 - 若合并逻辑较重,可考虑将结果暂存到 volatile 字段或
AtomicReference<t></t>,供主线程后续获取
常见陷阱与规避建议
Barrier action 执行期间其他线程挂起,所以务必避免在其中做耗时、阻塞或可能失败的操作(如 I/O、锁竞争、抛异常)——否则会拖慢甚至卡死整个屏障流程。
- 不要在 barrier action 中再次调用
await(),会导致死锁 - 若合并依赖某线程未完成的写入,确保该线程在
await()前已完成写入(推荐“先写后 await”模式) - 异常未捕获会直接导致 barrier 被中断,所有等待线程收到
BrokenBarrierException;建议在 action 中 try-catch 并记录日志










