AQS 的核心是“抽离共性 + 留出扩展点”,由 volatile int state(语义中枢,支持CAS原子操作)和 CLH 变体双向队列(维护等待顺序与唤醒依赖)构成,配合 tryAcquire/tryRelease 等模板方法及 LockSupport.park/unpark 底层调度实现高效灵活的同步控制。

AQS 的设计不是靠堆功能,而是靠“抽离共性 + 留出扩展点”,用极简的两个核心支撑起 ReentrantLock、Semaphore、CountDownLatch 等多种同步组件。
一个状态变量:volatile int state
state 是 AQS 的“语义中枢”,它本身不定义含义,只提供原子读写能力:
- 通过 getState()、setState() 和 compareAndSetState()(CAS)保证可见性与原子性
- 子类按需解释其值:ReentrantLock 用它记重入次数,Semaphore 用它剩许可证数,CountDownLatch 用它倒计时剩余数
- 用 int 而非 boolean,是为了兼容共享模式下多个线程同时持有资源的场景(比如允许多个线程通过的信号量)
一条虚拟队列:CLH 变体双向链表
这个队列不存数据,只维护线程等待顺序和唤醒依赖关系:
- 头节点(head)不绑定线程,仅作哨兵;尾节点(tail)指向最新入队线程
- 每个 Node 封装线程、前驱/后继指针、waitStatus(如 SIGNAL、CANCELLED),不依赖锁即可完成入队(CAS tail)、出队(移动 head)
- 唤醒逻辑解耦:当前节点释放资源后,只负责唤醒 直接后继(检查 waitStatus == SIGNAL),避免广播开销
两套模板方法:分离策略与机制
AQS 把“怎么排队/唤醒”全包了,只把最关键的资源判定逻辑交给子类实现:
- 独占模式:tryAcquire() 决定能否加锁,tryRelease() 决定能否解锁
- 共享模式:tryAcquireShared() 返回负数(失败)、0(刚好够)、正数(还有余量),tryReleaseShared() 控制是否传播唤醒
- 所有 acquire/release 入口都先调子类逻辑,失败才走队列流程——既保灵活性,又不牺牲性能
一套底层调度:LockSupport.park/unpark
绕过 synchronized 的监视器模型,直接对接操作系统线程原语:
- park() 让线程进入 WAITING 状态,不释放任何锁,也不要求在同步块中执行
- unpark(Thread) 可定向唤醒,比 Object.notify() 更可控,规避虚假唤醒和死锁风险
- 与 Node.waitStatus 协同:只有前驱节点是 head 且 tryAcquire 成功时,才真正获得资源;否则 park 前先设 SIGNAL,确保被唤醒后能继续竞争
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











