countdownlatch适用于一次性等待,不可重用;cyclicbarrier支持循环等待、具备屏障动作和破损传播机制,适合周期性协同。选型需据等待是否一次性、有无聚合操作及失败是否全局影响而定。

CountDownLatch 用错场景的典型表现
当需要等待多个线程「各自完成一次任务」后再统一继续,却用了 CountDownLatch,往往意味着设计偏差。它本质是「一次性门闩」:构造时指定计数,每次调用 countDown() 减一,await() 阻塞直到计数归零——之后再调用 await() 就直接返回,无法重置。
- 常见错误现象:
await()在第二次调用时不阻塞,导致后续逻辑提前执行 - 典型误用场景:模拟多轮并行计算(如每轮都需等所有 worker 完成),却没意识到
CountDownLatch不可重用 - 替代思路:若需循环等待,优先考虑
CyclicBarrier;若只是启动协调(如主线程等全部子线程初始化完毕),CountDownLatch是合适的
CyclicBarrier 的 barrierAction 容易被忽略的作用
CyclicBarrier 构造时可传入一个 Runnable 类型的 barrierAction,它会在最后一个线程调用 await()、但尚未释放其他线程前执行——这个时机非常关键,常被当成“可有可无的钩子”而跳过。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 实际价值:适合做汇总、校验、状态快照等「跨线程协同操作」,比如每轮结束时把各线程的局部结果合并到共享容器
- 注意点:该动作在持有屏障锁期间执行,应尽量轻量;若抛出异常,会导致所有等待线程收到
BrokenBarrierException - 参数差异:
CountDownLatch没有类似机制,想实现类似效果得手动加锁 + 条件判断,容易出竞态
两者对中断的响应方式不同
面试常问「如果线程在 await() 时被中断,会发生什么?」——答案取决于具体类:
-
CountDownLatch.await()被中断:立即抛出InterruptedException,计数器状态不变,其他线程不受影响 -
CyclicBarrier.await()被中断:抛出InterruptedException,同时触发屏障破损(isBroken() == true),所有已等待和将等待的线程都会收到BrokenBarrierException - 这意味着:
CyclicBarrier的中断具有「传染性」,适合强一致性要求的场景;而CountDownLatch更“隔离”,适合松耦合协调
别直接 new Thread 配合它们,用 ExecutorService 更稳
手写 new Thread(() -> { ... latch.countDown(); }).start(); 看似简单,但极易引发资源失控或异常丢失。真实项目中应搭配线程池使用:
ExecutorService pool = Executors.newFixedThreadPool(4);
CountDownLatch latch = new CountDownLatch(4);
for (int i = 0; i {
try {
// 执行任务
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
} finally {
latch.countDown();
}
});
}
latch.await(); // 主线程等待
pool.shutdown();
- 不捕获
InterruptedException直接吞掉,会导致中断信号丢失 - 务必在
finally块调用countDown()或await(),防止因异常导致计数卡死 -
CyclicBarrier同理,但要注意:若某个线程在barrierAction中抛异常,整个屏障就坏了,后续调用全失败
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










