countdownlatch用于主线程等待多个子任务完成,核心是内部计数器;初始化时指定任务总数且不可变,子任务在finally中调用countdown()确保递减,主线程调用await()阻塞等待,推荐使用带超时的重载并处理中断。

在 Java 中,CountDownLatch 是一个非常实用的同步工具类,适用于“主线程等待多个子任务全部完成后再继续执行”的典型场景。它的核心是基于一个内部计数器:每调用一次 countDown(),计数器减 1;当计数器归零时,所有因 await() 阻塞的线程被唤醒。
初始化 CountDownLatch 并设定任务总数
创建 CountDownLatch 实例时,必须传入预期的并发任务数量(即“要等待几个信号”)。这个数值应在启动任何子任务前确定,且不可更改。
- 例如有 3 个异步处理任务,就初始化为
new CountDownLatch(3) - 若任务数动态变化(如从集合中遍历提交),需先统计数量再构造,避免漏等或多等
每个子任务完成后调用 countDown()
子任务无论成功或失败,只要逻辑上“已结束”,都应在 finally 块中调用 countDown(),确保计数器一定递减。否则可能造成主线程永久阻塞。
- 推荐写法:
try { /* 执行任务 */ } finally { latch.countDown(); } - 不要只在 success 分支里调用,异常路径遗漏是常见 bug 来源
- 注意:
countDown()是线程安全的,可被多个线程并发调用
主线程调用 await() 等待所有任务完成
主线程在提交完所有子任务后,立即调用 latch.await()。该方法会阻塞当前线程,直到计数器变为 0 或被中断。
- 可选带超时的重载:
latch.await(10, TimeUnit.SECONDS),避免无限等待 - 若超时返回
false,说明仍有任务未完成,可根据业务决定是否重试、告警或放弃 -
await()可能抛出InterruptedException,需捕获并合理处理(如恢复中断状态)
完整示例:汇总 4 个 HTTP 请求结果后统一处理
(使用线程池 + CountDownLatch 模拟并发请求)
CountDownLatch latch = new CountDownLatch(4);
List<string> results = Collections.synchronizedList(new ArrayList());
<p>ExecutorService pool = Executors.newFixedThreadPool(4);
for (int i = 0; i {
try {
String res = callRemoteApi(taskId); // 模拟耗时操作
results.add(res);
} catch (Exception e) {
results.add("ERROR-" + taskId);
} finally {
latch.countDown();
}
});
}</p>
<p>try {
latch.await(30, TimeUnit.SECONDS); // 最多等 30 秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Waiting interrupted", e);
}</p>
<p>System.out.println("All done. Results: " + results);
pool.shutdown();
</p></string>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











