countdownlatch底层基于aqs共享模式实现:state为计数器,await()因tryacquireshared返回-1入队阻塞,countdown()通过cas递减state,归零时doreleaseshared批量唤醒所有等待线程。

CountDownLatch底层依赖AQS的共享模式
CountDownLatch不是靠自己实现线程协调,而是把核心逻辑完全委托给AbstractQueuedSynchronizer(AQS)。它采用AQS的共享锁模式,即多个线程可同时“获取”或“释放”状态,只要state值允许。其内部仅维护一个int类型的state变量——初始值为构造参数count,每次调用countDown()就对state执行CAS递减;当state归零,所有await()阻塞的线程被统一唤醒。
await()如何进入等待队列
调用await()时,会尝试以共享模式获取同步状态:
- 先调用AQS的acquireSharedInterruptibly(1),该方法内部调用tryAcquireShared(arg)
- CountDownLatch重写了tryAcquireShared:若state == 0,返回1(表示获取成功);否则返回-1(表示失败,需入队)
- 返回-1后,当前线程被封装为Node加入AQS的CLH同步队列,进入park()阻塞,等待后续被唤醒
countDown()如何触发唤醒
countDown()本质是共享模式下的释放操作:
- 调用AQS的releaseShared(1),最终进入tryReleaseShared(arg)
- CountDownLatch中该方法用CAS将state从n原子减为n−1;若减到0,返回true,表示“有资格唤醒后继”
- 一旦tryReleaseShared返回true,AQS就会调用doReleaseShared(),自旋唤醒同步队列中所有处于共享模式的头结点后继节点
- 注意:不是只唤醒一个,而是传播式唤醒——只要state==0,后续任意countDown()都不会再触发唤醒,但首次归零那次会批量放开所有await中的线程
唤醒过程的关键细节
doReleaseShared()是共享唤醒的核心,它不依赖条件判断,而是通过自旋+CAS修改waitStatus来确保唤醒动作可靠:
- 检查head是否变化,防止并发修改导致漏唤醒
- 对head.next(即第一个有效等待节点)调用unparkSuccessor(),解除其park阻塞
- 唤醒后,被唤醒线程回到acquireSharedInterruptibly流程,再次调用tryAcquireShared——此时state已为0,直接返回1并退出await
- 整个过程无锁、无synchronized,全部基于volatile+CAS,符合AQS“非阻塞同步器”的设计哲学
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











