countdownlatch通过共享计数器实现任务链阻塞等待,初始化值等于子任务数,各子任务末尾调用countdown(),主线程调用await()等待归零,且不可重用。

CountDownLatch 在任务链中实现阻塞等待,核心是用一个共享的计数器控制主线程(或协调线程)的等待时机——只有当所有前置子任务完成(计数器归零),后续任务才能继续执行。
明确任务链结构与 CountDownLatch 初始化
任务链通常表现为“多个并行子任务 → 汇总/后续处理”。CountDownLatch 的初始值必须等于待等待的子任务数量。例如:启动 3 个异步下载任务,主线程需等全部完成再解析数据,则构造时传入 3:
CountDownLatch latch = new CountDownLatch(3);在每个子任务末尾调用 countDown()
每个子任务(无论成功或失败)执行完毕后,必须调用 latch.countDown() 减少计数。这一步不能遗漏,也不能重复调用(除非逻辑上允许多次触发)。常见写法是在 try-finally 块中确保执行:
- Runnable 或 Callable 中,在业务逻辑结束后、finally 块内调用 countDown()
- 使用 CompletableFuture 时,可在 thenRun / whenComplete 后续动作里调用
- 若子任务抛异常,仍要保证 countDown() 执行,否则主线程永久阻塞
主线程用 await() 阻塞等待完成
协调线程(如主线程)在启动所有子任务后,立即调用 latch.await()。该方法会阻塞直到计数为 0,或被中断:
- 推荐使用带超时的版本 latch.await(10, TimeUnit.SECONDS),避免无限等待
- await() 返回 true 表示计数归零;返回 false 表示超时,此时应检查哪些子任务未完成
- 若被中断,会抛出 InterruptedException,需正确处理(恢复中断状态或退出)
注意不可重用性与替代方案
CountDownLatch 是一次性门闩:一旦计数归零,await() 不再阻塞,countDown() 也不再影响状态。如果任务链需要循环复用,应考虑:
- 每次任务链重新创建新的 CountDownLatch 实例
- 对复杂依赖场景(如 A→B、C→B),改用 Phaser 或 CompletableFuture 的组合编排(thenCombine、allOf)
- 若需响应式流控,可结合 BlockingQueue 或信号量 Semaphore 控制并发节奏
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











