CountDownLatch 是一次性等待工具,用于协调主线程等待多个任务完成,需严格匹配构造计数与 countDown() 次数,必须在 finally 块中调用 countDown(),推荐使用带超时的 await(),不可重置,不传递结果或支持异步回调。

CountDownLatch 不是用来“并行执行任务”的,而是用来“等待多个任务全部完成”的协调工具。它本身不启动线程,也不管理任务调度,只是提供一个阻塞点,让主线程(或某个协调线程)停在 await() 处,直到其他线程调用足够次数的 countDown()。
CountDownLatch 构造参数必须等于任务数
构造时传入的 count 值,代表你期望等待的“完成信号”总数。这个数必须和实际会调用 countDown() 的次数严格一致——通常是启动的子任务数量。
- 如果任务数是 3,却初始化为
new CountDownLatch(5),await()会永远卡住 - 如果任务数是 3,但只调用了 2 次
countDown()(比如某个线程异常退出没执行),同样卡死 - 推荐在提交任务前就确定计数值,并确保每个任务路径(包括 catch 块)都执行
countDown()
务必在每个子任务末尾调用 countDown(),且仅一次
countDown() 是无锁、原子、幂等的操作,但它不会自动触发,也不会因线程结束而隐式调用。漏掉、多调、或放在异常未覆盖的分支里,都会导致等待逻辑失效。
ExecutorService pool = Executors.newFixedThreadPool(3);
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
pool.submit(() -> {
try {
// 执行耗时操作
Thread.sleep(1000);
System.out.println("Task done");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // ✅ 必须放 finally,确保执行
}
});
}
latch.await(); // 主线程阻塞至此,直到三次 countDown 完成
System.out.println("All tasks finished");
pool.shutdown();
await() 可带超时,避免无限等待
生产环境绝不要裸用无参 await()。任务可能卡死、线程池满、或远程调用 hang 住,没有超时机制会导致整个流程不可恢复。
立即学习“Java免费学习笔记(深入)”;
- 使用
latch.await(30, TimeUnit.SECONDS)显式设上限 - 返回
false表示超时未完成,此时应主动处理:记录告警、中断剩余任务、或降级返回 - 注意:超时后
latch仍处于未完成状态,后续再调await()还会立即返回 false(除非重置——但 CountDownLatch 不可重置)
别把它当 CyclicBarrier 或 CompletableFuture 用
CountDownLatch 是一次性门闩(one-shot),不能重用;它不传递结果,也不组合异常;它不感知线程生命周期,也不支持异步回调。
- 需要重复使用?换
CyclicBarrier或自己封装 - 要收集每个任务的返回值?直接用
CompletableFuture.allOf()+thenApply() - 要响应式编排或错误传播?
CompletableFuture是更现代、更安全的选择 - 只是简单等 N 个线程做完就继续?CountDownLatch 依然轻量有效——前提是理解它的单次性与手动信号责任
最常被忽略的一点:CountDownLatch 的计数器归零后,所有正在 await() 的线程会被唤醒,但之后再调用 await() 会立即返回(因为状态已终态)。这意味着它适合“启动一批任务 → 等全部结束”这种单向流程,不适合动态增减任务或循环等待场景。


















