该用 CyclicBarrier 而不是 CountDownLatch 的场景是需要多线程分阶段协作且屏障可重用时,如多玩家回合同步、mini-batch 数据校验;因其可重置,而 CountDownLatch 仅适用于一次性初始化等待。
什么时候该用 CyclicBarrier 而不是 CountDownLatch
核心区别在于复用性:CyclicBarrier 可重置、可重复使用;CountDownLatch 一旦计数归零就不可逆。如果你的任务是「多线程分阶段协作」,比如每轮都需等所有线程到达某个检查点再一起继续(如并行计算的迭代步、模拟中的时间片同步),CyclicBarrier 更合适。
常见误用场景:用 CountDownLatch 做阶段性等待——结果只能用一次,第二轮就得新建实例,逻辑臃肿且易出竞态。
- 适合
CyclicBarrier:多玩家回合制游戏每轮同步、分布式测试中多个客户端统一启停、机器学习 mini-batch 训练前的数据校验同步 - 不适合:一次性初始化等待(如服务启动时加载配置),选
CountDownLatch更轻量
CyclicBarrier 构造与基本用法要点
最常用构造函数是 new CyclicBarrier(int parties),parties 表示需要等待的线程总数。注意:这个数必须和实际调用 await() 的线程数严格一致,少一个则永远阻塞,多一个会抛 BrokenBarrierException。
关键行为:每个线程调用 await() 后被挂起,直到第 parties 个线程调用,所有线程才同时唤醒继续执行。
立即学习“Java免费学习笔记(深入)”;
-
await()是可中断的,若线程在等待时被interrupt(),抛InterruptedException,屏障自动进入破损状态 - 可选构造函数
new CyclicBarrier(int parties, Runnable barrierAction),由最后一个到达的线程执行该回调,常用于汇总结果或日志记录 - 回调
barrierAction若抛异常,会导致所有等待线程收到BrokenBarrierException
如何安全处理 BrokenBarrierException 和屏障破损
BrokenBarrierException 不仅在屏障被中断时抛出,也出现在任一线程在 await() 中超时、异常退出、或 barrierAction 抛异常之后。此时屏障已损坏,后续所有 await() 都会立即抛该异常,除非手动重置。