CountDownLatch是一次性门闩,计数归零后不可重置,仅抛InterruptedException,适用于单次等待场景;CyclicBarrier是循环栅栏,计数可自动重置或手动reset,抛InterruptedException和BrokenBarrierException,强调全组同步成败一致,适用于多轮协同场景。

CountDownLatch 是“一次性门闩”,CyclicBarrier 是“循环栅栏”——这个比喻很准,关键就体现在计数能否重置和异常如何传播上。
计数器是否可重置
CountDownLatch 的计数器一旦归零,就彻底失效,无法 reset。它只服务一次等待逻辑:比如主线程等 3 个子任务完成,调用三次 countDown() 后计数变 0,所有阻塞在 await() 的线程被唤醒;之后再调用 await() 会直接返回,不再阻塞,也无法恢复计数。
CyclicBarrier 的计数器天生为重复使用设计。当全部线程到达屏障点、触发释放后,内部状态自动重置,可立即用于下一轮等待。你也可以主动调用 reset() 强制清空当前等待状态——哪怕还有线程正阻塞在 await(),它们会立刻收到 BrokenBarrierException 并退出。
- CountDownLatch:适合“启动一次、完成即弃”的场景,如初始化聚合、测试准备
- CyclicBarrier:适合“多轮协同、阶段推进”的场景,如分批计算、周期上报、游戏帧同步
异常处理机制不同
CountDownLatch 的 await() 只抛 InterruptedException。如果某线程被中断,仅该线程感知并退出,其他等待线程不受影响,继续等待计数归零。
CyclicBarrier 的 await() 会抛两种异常:InterruptedException 和 BrokenBarrierException。后者是核心差异——只要任意一个等待线程被中断、超时、或有人调用了 reset(),当前这一轮所有尚未通过屏障的线程都会收到 BrokenBarrierException,集体失败退出。这是“强一致性等待”的体现:要么全过,要么全崩。
- CountDownLatch:容错偏宽松,单点失败不影响整体等待逻辑
- CyclicBarrier:容错偏严格,一个线程出问题,整组同步失败
谁来驱动计数变化
CountDownLatch 的计数递减由外部控制:通常是子任务线程完成时调用 countDown();而主线程(或其他等待者)调用 await() 被动等待。
CyclicBarrier 的计数递减由参与者自身驱动:每个线程必须主动调用 await() 才算“到达”,最后一个到达的线程不仅自己被阻塞,还负责唤醒全体——它隐含了“协作发起”的语义。
- CountDownLatch:1 对多,主等子
- CyclicBarrier:多对多,子等子
不复杂但容易忽略:选错工具往往不是因为不会用,而是没看清“这次等待,是一锤定音,还是循环往复”。

















