CountDownLatch 通过“等完成”和“等开始”两种模式实现可控同步,避免无效等待。初始化计数须匹配任务数,子任务 finally 调用 countDown(),主线程用带超时的 await();启动场景用单次 countDown() 实现高并发起始;禁复用、避前置耗时、勿轮询 getCount()。

CountDownLatch 本身不“降低等待”,而是让等待更可控、更精准。它解决的不是等待时长问题,而是等待逻辑混乱、线程提前执行或永久阻塞的风险。真正降低无效等待的关键,在于用对它的两种典型模式:**等完成** 和 **等开始**。
用 await() + countDown() 确保“等完成”不卡死
主线程需要等多个子任务全部结束才能汇总结果?这是最常见场景。错误做法是靠 Thread.sleep() 硬等,或用 join() 逐个阻塞——既不灵活又难管理异常。
- 初始化时计数值必须严格等于实际启动的子任务数,多一个少一个都会导致 await() 不返回或提前返回
- 每个子任务的 finally 块中调用 countDown(),避免因异常、return 或中断跳过减计数
- 主线程调用 await(long, TimeUnit) 而非无参 await(),比如设为 30 秒超时,超时后可记录失败任务、释放资源,而不是无限挂起
用初始值为 1 的 latch 实现“并发启动”,消除启动偏差
当你要压测或模拟高并发请求,目标是让 100 个线程在同一毫秒级时刻开始执行——靠 new Thread().start() 无法保证,因为线程调度有延迟。
- 创建 CountDownLatch startLatch = new CountDownLatch(1)
- 所有工作线程启动后立即调用 startLatch.await(),全部挂起在同一点
- 主线程确认所有线程就绪(例如用另一个 finishLatch 或简单 sleep(10))后,只调用一次 startLatch.countDown()
- 所有等待线程瞬间被唤醒,执行时间差通常在微秒级,远优于裸启动
避免常见误用,减少隐性等待开销
很多“等待变长”其实来自使用不当,而非 CountDownLatch 本身慢:
立即学习“Java免费学习笔记(深入)”;
- 不要重复复用已归零的 latch:它不可重置。若需循环等待,改用 CyclicBarrier 或每次新建 latch
- 别在 await() 前做耗时操作:比如先查数据库再 await(),会把等待前的延迟也算进“等待时间”
- 不用 getCount() 做轮询判断:它只是快照值,轮询不仅浪费 CPU,还可能错过归零瞬间,应始终依赖 await()
本质上,CountDownLatch 把不确定的“猜时间”变成确定的“等信号”,让等待从被动等待转为主动协同。用对模式,等待就不再是瓶颈,而是可控的同步节点。


















