countdownlatch中await()线程被纳入aqs同步队列:state>0时入队并park阻塞,支持中断与超时;state=0时批量唤醒所有等待线程,确保强一致性。

CountDownLatch 中调用 await() 的线程,不是简单“睡着等”,而是被纳入 AQS(AbstractQueuedSynchronizer)维护的同步等待队列,这是它高效、可中断、支持超时的关键。
等待线程实际进入 AQS 共享模式同步队列
CountDownLatch 内部的 Sync 类继承自 AQS,并把计数器值直接存入 AQS 的 state 字段。当线程调用 await() 时:
- 它会尝试以共享模式获取同步状态(即检查 state 是否为 0)
- 若 state > 0,当前线程会被封装成一个Node 节点,通过 CAS 安全地插入 AQS 的双向 FIFO 同步队列尾部
- 插入成功后,线程会调用 LockSupport.park() 进入阻塞状态,但仍保留在队列中可被唤醒
- 这个队列是真实的、由 AQS 管理的线程等待链表,不是用户态轮询或 Thread.sleep 模拟
阻塞不等于挂起整个 JVM,而是精准受控
进入队列的线程处于 WAITING 或 TIMED_WAITING 状态(取决于是否带超时),但它们:
- 不会消耗 CPU 时间片,JVM 可安全调度其他线程
- 可响应 interrupt —— 被中断时会清理队列节点并抛出 InterruptedException
- 支持超时:await(long, TimeUnit) 会在 park 时设置超时参数,到期自动退出阻塞并返回 false
- 只在 state 变为 0 或中断/超时时才被唤醒,无虚假唤醒风险
唤醒过程是批量、一次性释放所有等待者
当最后一个 countDown() 将 state 减至 0 时:
- AQS 的 doReleaseShared() 逻辑被触发
- 它从同步队列头开始遍历,对每个阻塞的 Node 调用 unpark() 唤醒对应线程
- 被唤醒的线程重新竞争检查 state —— 此时已为 0,于是退出 await() 继续执行
- 注意:不是逐个唤醒,也不是按优先级,而是“全部放行”,保证强一致性
主线程和子线程角色完全对称,但行为不同
谁调用 await(),谁进队列;谁调用 countDown(),谁只是做 CAS 减 state:
- 主线程调用 await() → 进入同步队列阻塞
- 多个子线程调用 countDown() → 不入队,仅原子更新 state,可能触发唤醒
- 哪怕只有 1 个线程 await(),它也会独占整个队列;哪怕有 100 个线程 await(),它们都在同一队列里等待统一信号
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











