CountDownLatch 是一次性等待工具,用于让线程等待N个操作全部完成;必须严格匹配初始化计数与countDown()调用次数,需带超时的await、finally中调用countDown、不可复用或误作循环控制。

CountDownLatch 是 Java 并发编程中最常用、最直观的协作工具之一,核心价值在于“等待一组操作全部完成”。它不负责任务调度或资源争抢,只做一件事:让一个或多个线程精准卡在某个节点,直到预设的 N 个条件(通常是 N 个子任务)全部达成。
初始化与计数逻辑必须匹配真实任务数
构造 CountDownLatch 时传入的数值,必须严格等于你预期调用 countDown() 的总次数。少一次,await() 永远阻塞;多一次,虽不报错但语义错误,可能掩盖逻辑漏洞。
- 推荐在创建前就明确任务粒度——是按线程数?按接口调用次数?还是按数据分片数量?
- 避免在异常分支中遗漏 countDown()。建议把 countDown() 放在 finally 块里,确保无论成功失败都递减
- 如果任务本身支持重试,不要在每次重试都 countDown(),应只在最终确认完成时调用一次
主线程等待要带超时,防止无限挂起
生产环境严禁无保护的 latch.await()。一旦某个子任务因异常、死锁或网络故障卡住,主线程将永久阻塞,导致服务不可用。
- 始终优先使用 latch.await(30, TimeUnit.SECONDS) 这类带超时的版本
- 超时后需检查 getCount() 值,判断还有几个任务未完成,便于日志定位或降级处理
- 超时返回 false 时,不应直接抛异常,而应记录告警、清理资源、走备用逻辑(如返回缓存结果)
别把它当循环控制器或状态开关用
CountDownLatch 是一次性门闩,state 归零后无法 reset,也不能反向加值。它不是 CyclicBarrier,也不是 Semaphore。
立即学习“Java免费学习笔记(深入)”;
- 需要重复等待场景(如定时批量任务),应每次新建 CountDownLatch 实例,而非复用旧对象
- 不要试图用它实现“等待任意一个完成”或“等待前 N 个完成”,这类需求更适合 CompletableFuture 或 Phaser
- 它不感知线程生命周期,也不保证执行顺序——仅计数,不调度
与线程池配合时注意资源释放时机
常见误操作是在线程池 submit 后立即 shutdown,导致未执行完的任务被中断,countDown() 无法触发。
- 正确做法:先 await() 等待所有任务逻辑完成,再 shutdown() 或 shutdownNow()
- 若使用 Spring 的 ThreadPoolTaskExecutor,可通过 awaitTermination() 配合 CountDownLatch 实现优雅停机
- 异步回调场景中(如 CompletableFuture.thenRun),确保 countDown() 在回调内执行,而非在 submit 返回后立刻调用


















