countdownlatch 是基于 aqs 的一次性同步工具,通过初始化计数器并调用 countdown() 递减、await() 阻塞等待归零来实现主线程等待多线程完成;需确保 count 值准确、countdown() 在 finally 中调用,并避免与 cyclicbarrier 等混淆。

CountDownLatch 是 Java 并发包中用于线程间同步的工具类,核心作用就是让主线程等待一组子线程全部执行完毕后再继续执行。它基于 AQS(AbstractQueuedSynchronizer)实现,内部维护一个计数器,每调用一次 countDown() 方法就减 1,当计数器归零时,所有因 await() 阻塞的线程被唤醒。
初始化 CountDownLatch 时指定子线程数量
构造函数 new CountDownLatch(int count) 中的 count 必须等于你预期启动的子线程数量(或任务数)。这个值不能动态修改,且一旦归零就不可重置——如果需要重复使用,应考虑 CyclicBarrier。
- 若实际启动线程数少于设定值,主线程会永久阻塞在
await() - 若多于设定值,多余的
countDown()不影响结果,但属于逻辑错误,应避免 - 推荐在创建前明确任务总数,例如:
CountDownLatch latch = new CountDownLatch(tasks.size());
每个子线程完成任务后调用 countDown()
子线程必须在自身逻辑执行完毕(尤其是关键操作结束)后主动调用 latch.countDown()。常见做法是在 try-finally 块中确保即使发生异常也能触发计数减一。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 错误写法:只在正常流程末尾调用,异常时漏掉
- 正确写法:放在 finally 块中,保证释放信号
- 示例:
try { /* 执行任务 */ } finally { latch.countDown(); }
主线程调用 await() 等待所有子线程完成
主线程在启动所有子线程后,立即调用 latch.await()。该方法会阻塞当前线程,直到计数器变为 0 或被中断。
- 可选带超时的版本:
latch.await(10, TimeUnit.SECONDS),避免无限等待 - 若超时未完成,
await()返回false,需自行处理超时逻辑(如取消任务、记录告警) - 若被中断,抛出
InterruptedException,应合理捕获并恢复中断状态(Thread.currentThread().interrupt();)
注意与其他同步机制的区别
CountDownLatch 是一次性门闩,不关心线程身份,只关注“事件发生次数”。它不是锁,也不控制临界区访问;和 join() 不同,它不要求知道具体哪个线程,适合解耦任务调度与等待逻辑。
- 不用为每个线程单独调用
join(),尤其适合线程池场景 - 不能像
Semaphore那样控制并发数,也不能像CyclicBarrier那样复用 - 典型适用场景:批量异步请求汇总、服务启动检查、测试中模拟并发准备
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










