CountDownLatch 是 Java 并发包中基于原子计数器实现线程协同等待的工具,通过 countDown() 减计数、await() 阻塞等待,计数归零后不可重置;常用于主线程等待多子任务完成,需注意避免漏调 countDown() 或重复使用实例。

CountDownLatch 是 Java 并发包(java.util.concurrent)中用于线程协同等待的核心工具之一。它的核心作用是:**让一个或多个线程等待,直到其他线程完成一组操作后才继续执行**。它不涉及锁竞争,而是基于内部计数器的原子减法与阻塞机制实现协调。
CountDownLatch 的基本原理
它内部维护一个初始为 n 的计数器。每次调用 countDown() 方法,计数器原子减 1;当计数器变为 0 时,所有因调用 await() 而阻塞的线程会被唤醒并继续执行。计数器一旦归零,后续再调用 await() 将直接返回(不阻塞),且无法重置——这是它和 CyclicBarrier 的关键区别。
典型使用场景:主线程等待多个子任务完成
比如启动 5 个线程并发处理数据,主线程需等全部处理完再汇总结果:
- 创建
CountDownLatch latch = new CountDownLatch(5) - 每个子线程执行完自己的任务后调用
latch.countDown() - 主线程在关键位置调用
latch.await()—— 此处会阻塞,直到 5 次countDown()全部执行完毕
注意 await 的可中断与超时控制
await() 有带超时和不带超时两个重载版本:
-
latch.await():无限等待,直到计数归零(可能被中断) -
latch.await(3, TimeUnit.SECONDS):最多等 3 秒,超时返回false;若期间计数归零则立即返回true
若线程在 await() 中被中断,会抛出 InterruptedException,需合理捕获并处理(如恢复中断状态或退出逻辑)。
常见误用与规避建议
- 不要重复初始化同一个 latch 实例来复用——它不可重置。需要多次协同时,应新建实例
- 确保每个参与协作的线程都执行了
countDown(),漏调会导致主线程永久阻塞 - 避免在
countDown()前发生异常而跳过调用,建议用try-finally包裹关键逻辑 -
await()应放在真正需要等待的位置,而不是在循环里反复调用(无意义且低效)
不复杂但容易忽略细节。用对了,就能干净利落地解决“等全部做完再继续”的问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











