CountDownLatch` 是 Java 并发编程(java.util.concurrent)中的同步辅助工具类,其核心作用是**让一个或多个线程等待其他线程完成操作**。它通过内置的计数器实现线程协调,适用于多线程场景下的任务分治和结果聚合。
核心机制
- 计数器初始化
创建时指定初始计数值(正整数): - java
- 复制代码
- CountDownLatch latch = new CountDownLatch(3); // 初始计数器=3
- 线程阻塞
调用 await() 的线程会被阻塞,直到计数器归零: - java
- 复制代码
- latch.await(); // 阻塞当前线程,直到计数器变为0
- 计数器递减
其他线程完成任务后调用 countDown() 使计数器减 1: - java
- 复制代码
- latch.countDown(); // 计数器减1(线程安全操作)
典型应用场景
场景 1:主线程等待所有子线程就绪
java
// 模拟服务器启动(主线程需等待所有组件初始化完成)
CountDownLatch latch = new CountDownLatch(3);
new Thread(() -> {
initDatabase(); // 初始化数据库
latch.countDown();
}).start();
new Thread(() -> {
initCache(); // 初始化缓存
latch.countDown();
}).start();
new Thread(() -> {
loadConfig(); // 加载配置
latch.countDown();
}).start();
latch.await(); // 阻塞主线程,直到3个子线程完成初始化
startServer(); // 所有组件就绪后启动服务
场景 2:并行任务结果聚合
java
// 多线程计算后汇总结果
List<Integer> results = Collections.synchronizedList(new ArrayList<>());
CountDownLatch latch = new CountDownLatch(4);
IntStream.range(0, 4).forEach(i ->
new Thread(() -> {
results.add(calculateSegment(i)); // 分段计算
latch.countDown();
}).start()
);
latch.await(); // 等待所有计算线程结束
int total = results.stream().mapToInt(Integer::intValue).sum();
关键特性
特性 | 说明 |
一次性 | 计数器归零后不可重置(如需重用,改用 CyclicBarrier) |
线程安全 | 基于 CAS 实现,无需额外同步 |
阻塞非中断 | await() 会阻塞至计数归零,但支持带超时版本:await(long timeout, TimeUnit unit) |
无死锁风险 | 即使未调用足够次数的 countDown(),也可通过超时机制避免永久阻塞 |
与类似工具对比
工具 | 重用性 | 核心能力 | 适用场景 |
CountDownLatch | 一次性 | 等待事件完成 | 启动预备、任务分治 |
CyclicBarrier | 可重置 | 线程相互等待 | 分阶段并行计算 |
CompletableFuture | 链式操作 | 异步任务编排 | 复杂依赖的任务流水线 |
最佳实践:在微服务启动、分布式测试、MapReduce 式计算等需要等待前置条件满足的场景优先使用 CountDownLatch,其简洁性优于 synchronized 或 wait()/notify()。
通过计数器机制,CountDownLatch 以极低开销实现了高效的线程协调,是 Java 并发工具箱中的基础同步原语。