CountDownLatch适用于一次性等待所有操作完成,不可重置;CyclicBarrier适用于多线程循环协同,可重置并支持屏障中断与回调。二者语义不同,不可互换。

CountDownLatch 适合“等待一组操作全部完成”
它是一次性使用的计数器,初始化时指定一个 count,每次调用 countDown() 就减一,调用 await() 的线程会阻塞直到计数归零。常见于:主线程等所有子任务跑完再继续、服务启动时等待多个组件初始化完毕。
注意点:
-
CountDownLatch不能重置,一旦计数到 0,后续所有await()都立即返回 - 没有“唤醒所有等待线程后自动重置”的机制,所以不适合循环场景
- 如果某线程调用
await()后被中断,会抛InterruptedException,需自行处理
CyclicBarrier 适合“多线程分阶段协同执行”
它更像一个“集合点”,多个线程各自执行一段逻辑后,在 await() 处等待彼此到达;当最后一个线程到达,所有线程同时被释放,并可选择执行一个 Runnable(如汇总统计)。典型场景:并行计算分片处理 + 汇总、多玩家准备就绪后开始游戏回合。
关键行为:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
-
CyclicBarrier可重复使用,计数归零后自动重置为初始值 - 支持带超时的
await(long timeout, TimeUnit unit),超时后会抛TimeoutException并打破屏障 - 任一线程在
await()时被中断或超时,整个屏障进入broke状态,其他等待线程也会收到BrokenBarrierException
别把它们当“可互换的等待工具”用
表面上都让线程等,但设计意图完全不同:
- 用
CountDownLatch实现“多线程等一个信号”很简单,但反过来模拟CyclicBarrier的循环协作就得自己加锁 + 重置逻辑,容易出错 - 用
CyclicBarrier做一次性等待也可以,但它的异常传播机制(BrokenBarrierException)和重入特性在单次场景里是冗余负担 - 性能上差异不大,但语义误用会导致调试困难——比如看到
BrokenBarrierException却用了CountDownLatch,说明代码逻辑和工具选型不匹配
一个容易忽略的细节:线程到达顺序不影响 CyclicBarrier 行为
CyclicBarrier 不关心谁先到、谁后到,只关心“是否凑够 parties 个”。但要注意:Runnable 回调(如果设置了)是由最后一个到达的线程执行的,不是由某个固定线程执行。这意味着:
- 回调里不要做耗时操作,否则会拖慢最后一个线程,进而影响下一轮等待的启动
- 回调中若抛异常,会导致所有等待线程收到
BrokenBarrierException - 如果想在回调里安全更新共享状态,得确保该状态本身是线程安全的,或者回调已处于临界区保护下

















