CountDownLatch 是 Java 并发包中用于线程等待的同步辅助类,通过 volatile int 计数器实现:构造时设初始值,countDown() 原子减一,await() 阻塞至归零;不可重置,适用于主线程等待多任务完成等场景。

CountDownLatch 是 Java 并发包(java.util.concurrent)中一个轻量级的同步辅助类,用于让一个或多个线程等待其他线程完成一组操作后再继续执行。它不是锁,而是一个“计数器闭锁”——初始化时设定一个计数值,每次调用 countDown() 就减一,当计数变为 0 时,所有因 await() 阻塞的线程被唤醒并继续运行。
核心机制:计数器归零即释放等待
CountDownLatch 的行为由内部一个 volatile int 计数器控制:
- 构造时传入正整数
count,表示需要等待的事件数量(比如启动 5 个任务,就设为 5) - 调用
await()的线程会阻塞,直到计数器变为 0 或被中断 - 调用
countDown()的线程会将计数器原子性地减 1;多个线程可并发调用,无需额外同步 - 计数器一旦归零,后续所有
await()调用立即返回,且无法重置(不可重用)
典型使用场景:主线程等子任务全部完成
比如启动多个异步任务(如数据加载、IO 请求),主线程需等它们全部结束才进行汇总处理:
- 创建
CountDownLatch latch = new CountDownLatch(3)表示等 3 个任务 - 每个子线程执行完自己的逻辑后调用
latch.countDown() - 主线程在最后调用
latch.await()—— 若此时计数未到 0,就会挂起 - 只要三个子线程都调用了
countDown(),主线程立刻恢复执行
带超时的等待更健壮
避免因某个线程异常未调用 countDown() 导致永久阻塞:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
- 用
latch.await(10, TimeUnit.SECONDS)设置最长等待时间 - 方法返回
true表示计数已归零;返回false表示超时,此时可做降级处理(如记录告警、跳过部分结果) - 注意:超时后
await()返回,但计数器状态不变;若之后仍有线程调用countDown(),不会影响已返回的线程
常见误区与注意事项
使用时容易忽略的关键点:
- CountDownLatch 是一次性用品:计数归零后不能 reset,需新建实例才能复用
-
countDown()可被任意线程调用,不限于创建它的线程或 worker 线程 - 不要在
await()后假设所有子线程一定“刚完成”——它们可能早已结束,也可能刚结束,但顺序不保证 - 若需“等待开始”而非“等待结束”,应考虑
CyclicBarrier或Phaser,而不是强行倒置 CountDownLatch 用法
不复杂但容易忽略细节,掌握计数逻辑和生命周期就能稳妥落地。


















