countdownlatch 是 java 中用于等待多个子任务完成的轻量级同步工具,其核心是基于 aqs 的 volatile int 计数器,通过 countdown() 减计数、await() 阻塞等待归零,需配合 try-finally 防漏调、超时控制防卡死,并可与 completablefuture 结合提升异常处理与结果编排能力。

CountDownLatch 是 Java 并发编程中专为“等待多个子任务完成”设计的轻量级同步工具,它不抢锁、不共享变量、不依赖线程生命周期,只做一件事:让主线程(或协调线程)安心等到所有子任务调用 countDown() 把计数器归零后再继续执行。
CountDownLatch 的核心行为要清楚
它内部持有一个 volatile int 计数器,由 AQS(AbstractQueuedSynchronizer)保障线程安全:
- 构造时指定总数(比如 new CountDownLatch(5)),这个数必须等于最终会成功调用
countDown()的次数 -
countDown()是非阻塞操作,可在任意线程中多次调用,每次减 1,不可逆,也不可重置 -
await()会让当前线程阻塞,直到计数器为 0 或被中断;带超时的await(10, SECONDS)更适合生产环境 - 计数器归零后,所有阻塞在
await()上的线程会被唤醒,且后续再调用await()会立即返回
主线程等待多个子任务完成的标准写法
以启动 4 个异步数据加载任务为例:
- 创建 latch:
CountDownLatch latch = new CountDownLatch(4); - 每个子任务(无论用 Thread、ExecutorService 还是 CompletableFuture)在业务逻辑结束后,务必在
finally块里调用latch.countDown() - 主线程启动全部任务后,立刻调用
latch.await(30, SECONDS)—— 不是无限等,超时需判断返回值 - 若返回
true,说明全部完成,可安全汇总结果;若false,按需降级、告警或清理资源
避免卡死和丢任务的实操要点
很多问题不是 CountDownLatch 本身的问题,而是使用方式偏差:
- 漏调
countDown()最常见于异常路径——必须用try-finally包裹,哪怕任务抛出 RuntimeException 也要扣减 - 别用非线程安全集合(如 ArrayList)直接存子任务结果;推荐
ConcurrentHashMap或CopyOnWriteArrayList,或用AtomicReference存汇总状态 - 初始化数量要严格匹配实际执行的子任务数;如果用了线程池 submit,确认任务真被提交(注意拒绝策略可能丢任务)
- 调试时可临时加
System.out.println("remaining: " + latch.getCount());,快速定位哪个任务没减
和 CompletableFuture 配合更进一步
CountDownLatch 只管“是否完成”,不管“结果如何”或“有没有异常”。需要统一处理返回值、异常传播、链式编排时,建议把它作为底层机制封装进 CompletableFuture:
- 每个子任务用
CompletableFuture.supplyAsync(...)提交,完成时触发latch.countDown() - 主线程用
CompletableFuture.allOf(...).join()等待全部完成,天然支持异常收集与组合逻辑 - 这样既保留了 CountDownLatch 的简洁同步语义,又获得 CompletableFuture 的表达力和健壮性











