CountDownLatch适用于一次性等待操作完成,CyclicBarrier适用于多轮线程协同;前者不可重置、异常不传播,后者可循环、异常导致屏障破裂并需手动恢复。

CountDownLatch 和 CyclicBarrier 都用于线程同步,但设计目标完全不同:前者解决「等待一批操作结束」,后者解决「多线程分阶段协同」。关键不在“谁更强大”,而在“谁更适合当前场景”。
核心行为差异:一次性门闩 vs 可循环集合点
CountDownLatch 是单次使用的倒计时门闩:初始化为 N,每调用一次 countDown() 计数减 1;当计数归零,所有在 await() 处阻塞的线程被唤醒;之后再调用 await() 会直接返回,无法重置。
CyclicBarrier 是可重复触发的同步点:初始化为 N,每个线程调用 await() 后进入等待;第 N 个线程到达时,所有线程同时释放;释放后内部计数自动归位,下一轮可继续使用。
- CountDownLatch:适合“启动信号”或“完成汇总”——比如主线程等 3 个子任务全部跑完再统计结果
- CyclicBarrier:适合“多轮协作”——比如并行计算中,每轮都需所有线程完成局部计算、再一起汇总、再进入下一轮迭代
异常处理方式不同:失败传播 vs 局部中断
CountDownLatch 对线程异常不敏感:某个子线程抛异常未调用 countDown(),计数器卡在非零值,await() 永远阻塞(除非设超时)。
CyclicBarrier 更严格:任一参与线程在 await() 中被中断、超时或抛出未捕获异常,整个屏障将被打破(broken),后续所有 await() 调用立即抛出 BrokenBarrierException;可通过 isBroken() 检查状态,或用 reset() 手动恢复(但需确保无线程正在 await)。
- 这意味着 CyclicBarrier 更适合对一致性要求高的协同场景,但也更“脆弱”
- CountDownLatch 更“宽容”,但也更难发现遗漏的 countDown()
底层实现机制不同:共享锁 vs 可重入锁+条件队列
CountDownLatch 基于 AQS 的共享模式,用 state 字段存剩余计数,await() 对应 acquireShared,countDown() 对应 releaseShared。
CyclicBarrier 不依赖 AQS,而是封装了 ReentrantLock 和 Condition:每次 await() 都在同一个 condition 上 await(),最后一个线程 signalAll() 唤醒全部。
- 所以 CyclicBarrier 支持回调(barrierAction),在每次屏障触发前执行一次定制逻辑
- CountDownLatch 没有内置回调,需在 countDown() 后手动安排,或靠 await() 返回后统一处理
典型误用场景提醒
新手常把两者混用,例如:
- 用 CyclicBarrier 让主线程等子线程完成(应选 CountDownLatch)——CyclicBarrier 要求所有参与者都调 await(),主线程不是“工作线程”却占一个名额,易导致死等
- 用 CountDownLatch 实现多轮批处理(如每轮 10 个任务)——每轮都要 new 新实例,对象创建开销大,且无法复用状态
- 忽略 CyclicBarrier 的 broken 状态,在异常后未 reset 就继续 await(),结果持续抛异常










