countdownlatch 是 java 并发包中用于主线程等待多个子任务完成的同步工具,基于不可重置的倒计时计数器,需配合线程安全容器收集结果并注意异常处理与超时控制。

CountDownLatch 是 Java 并发包中用于线程同步的实用工具,特别适合“主线程等待多个子任务全部完成”的场景。它不关心任务执行细节,只通过计数器控制阻塞与释放,逻辑清晰、使用轻量。
核心原理:倒计时门闩机制
CountDownLatch 内部维护一个 int 类型的计数器,初始化时指定总数(如 new CountDownLatch(5) 表示需等待 5 个事件)。每次调用 countDown(),计数器减 1;主线程调用 await() 会阻塞,直到计数器归零或超时。注意:计数器不可重置,一旦归零,后续所有 await() 将立即返回。
典型用法:主线程汇总子任务结果
实际开发中,常需并发执行多个子任务(如批量查库、远程调用),再统一处理结果。CountDownLatch 本身不传递数据,需配合其他结构(如 List、AtomicInteger、ConcurrentHashMap)收集结果:
- 定义线程安全的容器(如 CopyOnWriteArrayList 或 ConcurrentHashMap)存储各子任务输出
- 每个子任务在线程中执行完毕后,先保存结果,再调用 latch.countDown()
- 主线程在启动所有子任务后,调用 latch.await() 阻塞等待
- await 返回后,直接读取共享容器中的全部结果进行汇总
避免常见陷阱
使用不当易引发死锁或逻辑错误:
- 不要在子任务中遗漏 countDown():异常未捕获导致 countDown 没执行,主线程永久阻塞。建议在 finally 块中调用
- await 应配合超时参数:如 latch.await(30, TimeUnit.SECONDS),防止因子任务卡死导致主线程无限等待
- CountDownLatch 不替代线程池管理:它不创建线程,通常与 ExecutorService 配合使用——由线程池提交任务,主线程用 latch 等待
- 结果收集需保证线程安全:若用普通 ArrayList 或 HashMap,多线程写入会出错;优先选并发集合或加锁
一个精简可运行示例
模拟 3 个子任务并行计算,主线程等待并打印总和:
CountDownLatch latch = new CountDownLatch(3);
List<integer> results = Collections.synchronizedList(new ArrayList());
<p>ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i {
try {
int res = taskId * 10 + 5; // 模拟耗时计算
results.add(res);
} finally {
latch.countDown(); // 确保执行
}
});
}</p>
<p>latch.await(10, TimeUnit.SECONDS); // 最多等 10 秒
pool.shutdown();</p>
<p>int sum = results.stream().mapToInt(Integer::intValue).sum();
System.out.println("汇总结果:" + sum); // 输出:75(5+15+55)
</p></integer>










