countdownlatch 的核心机制是主线程调用 await() 会一直阻塞直到计数器减为 0,此时所有 await() 线程被自动、广播式唤醒;计数器归零后不可重置,需注意异常漏调 countdown() 和超时控制。

在 Java 中,CountDownLatch 的核心机制就是:主线程调用 await() 会**一直阻塞**,直到内部计数器减为 0;一旦归零,所有正在 await() 的线程(包括主线程)会**立即被唤醒**,无需额外通知。
主线程如何正确阻塞等待归零
主线程只需调用 countDownLatch.await() 即可进入阻塞状态。该方法是可中断的,会释放锁并挂起当前线程,直到计数器变为 0 或线程被中断。
- 如果计数器已为 0,
await()立即返回,不阻塞 - 若计数器 > 0,主线程进入 WAITING 状态,CPU 不再调度它执行
- 推荐配合超时使用:
await(10, TimeUnit.SECONDS),避免永久阻塞
其他线程如何触发“瞬间唤醒”
唤醒不是由某个线程主动“发信号”,而是由最后一个调用 countDown() 并使计数器从 1 减到 0 的线程**自动触发**的。此时 JVM 内部会唤醒所有因 await() 阻塞的线程。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 多个线程可并发调用
countDown(),但只有将计数器减至 0 的那一次操作才会触发唤醒 - 唤醒是“广播式”的:所有等待中的线程(无论多少个)都会在同一时刻脱离阻塞状态
- 注意:唤醒后线程恢复执行的顺序取决于线程调度器,不保证与阻塞顺序一致
典型使用模式示例
常见于“主线程等待多个子任务完成”的场景,例如启动 3 个异步任务后统一汇总结果:
- 初始化:
CountDownLatch latch = new CountDownLatch(3); - 每个子线程执行完任务后调用
latch.countDown(); - 主线程在启动全部子线程后立即调用
latch.await();—— 此时开始阻塞 - 当第 3 个子线程调用
countDown()后,计数器变 0,主线程立刻继续执行后续逻辑
注意事项和常见误区
CountDownLatch 是一次性使用的,计数器归零后无法重置。若需重复使用,请考虑 CyclicBarrier 或手动重建实例。
- 不要在
await()前忘记启动子任务,否则主线程可能永远阻塞 - 避免在
countDown()前发生异常导致漏调用,可用 try-finally 保障 -
await()返回后,应检查是否因中断或超时退出,而非默认认为计数器已归零
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










