AQS 的核心原理是什么,如何管理同步状态、CAS 与锁重入?
未标记
考查重点:同步状态与等待队列。AQS 用 state 表资源,CAS 尝试获取,失败入等待队列,释放后唤醒;可重入锁用持有线程和计数表达重入
本题目录
参考答案
核心回答
AQS,即 AbstractQueuedSynchronizer,是 Java 中构建锁和同步器的框架。它把同步状态管理、竞争失败后的排队与等待、释放后的唤醒组织起来;子类负责定义什么条件下可以获取资源、怎样释放资源。ReentrantLock、Semaphore、CountDownLatch 都使用了它。
核心可以分成三部分:
- 同步状态
state:AQS使用volatile int保存状态,并提供读取、设置和CAS更新方法。状态含义由具体同步器决定,例如ReentrantLock的持有次数、Semaphore的可用许可数,含义并不相同。 - 等待队列与阻塞唤醒:线程先尝试获取资源;失败后,按相应获取方式进入等待流程,必要时排队、阻塞。资源释放后,后继等待者获得继续尝试的机会。被唤醒不等于已经拿到锁。
- 模板方法分工:
AQS提供 acquire/release 等流程,子类实现tryAcquire/tryRelease或共享模式的相应方法,决定状态变化和获取规则。
可重入也由具体锁实现,不是 AQS 自动赋予所有同步器的能力。 ReentrantLock 记录拥有者:空闲时通过 CAS 争取状态并设置拥有者;同一线程再次获取时增加持有次数;释放时减少次数,降到零才完全释放。
进一步解释
CAS、volatile 与等待队列各解决什么?
CAS 让“状态仍等于预期值时才修改”成为原子操作,适合多个线程竞争空闲资源等场景。volatile 提供状态读写所需的可见性和顺序语义,但不会把任意读改写自动变成原子操作。
等待队列则组织竞争失败的线程,避免所有等待者始终对同一个状态忙等。以 JDK 25 的实现为例,AQS 使用 CLH 变体队列,获取流程中会重试、维护节点状态,并在适当时通过 LockSupport 进入等待;中断、超时等还会触发取消处理。不能概括成“CAS 一失败就立即睡眠”,也不能说 AQS 是纯自旋锁。
三者配合的是资源获取协议;业务代码仍要正确使用同步器,例如持锁范围、释放时机和共享数据访问都要一致。
ReentrantLock 重入和释放的过程是什么?
假设线程 A 第一次获取锁,state 从 0 变成 1,拥有者设为 A。A 在内部方法中再次获取同一把锁,因为拥有者仍是自己,持有次数增加到 2;它不会把自己放进等待队列。
这时线程 B 尝试获取,发现状态不允许且拥有者不是自己,就进入等待流程。A 第一次 unlock 只是把计数减到 1,锁仍由 A 持有;第二次 unlock 才降到 0、清除拥有者,并让后续等待者继续竞争。
同一拥有者修改重入计数时,并不需要把每次增减都写成竞争性的 CAS。未持有锁的线程释放锁,则会被拒绝。重入增加了几次,就需要匹配地释放几次。
独占模式、共享模式和 Condition 有什么关系?
独占模式通常只允许一个线程获取资源;共享模式按子类规则允许多个线程通过,例如信号量按许可数放行。CountDownLatch 则在计数降到零后允许等待者通过,说明 state 为零不能统一解释为“没有可用资源”。
ConditionObject 维护的是条件等待者。以可重入独占锁为例,await 保存获取状态、完全释放锁并等待;signal 把条件等待者移到所属锁的等待队列,等待者之后仍需重新获取锁,并恢复相应持有状态。条件队列与争取锁的同步队列不能混为一谈。
常见追问
队列是 FIFO,为什么还能有非公平锁?
FIFO 描述等待队列的组织,不等于 AQS 强制所有获取都按到达顺序发生。新线程可能先尝试获取而插队。具体同步器可以在获取逻辑中检查排队前驱,形成相应公平策略;是否公平取决于实现和所调用的获取方法。
ReentrantReadWriteLock 怎么区分读写状态?
它组合了共享读和独占写,需要分别记录读、写持有信息。但具体状态布局要看版本:常见 JDK 8 源码采用 AQS 的 int 分区;JDK 25 实现已使用 AbstractQueuedLongSynchronizer 的 long 状态。不要把旧版高低位布局当成所有 JDK 或所有 AQS 同步器的固定规则。
synchronized 也是基于 AQS 吗?
不是。synchronized 由 JVM 的对象监视器等机制支持;AQS 是类库层的同步器框架。两者都能提供同步能力,不代表内部实现相同。
参考资料
- 国内:JavaGuide:AQS 详解:采用同步器框架、模板方法和状态含义的介绍,建立“获取规则由子类定义,排队等待由框架组织”的主线。
- 国内:美团技术团队:从 ReentrantLock 的实现看 AQS 的原理及应用(JavaGuide 收录):采用独占锁竞争中 state 与拥有者配合的过程,解释正文的可重入计数;文章基于 JDK 8,节点字段和等待实现仍按正文所用版本区分。
- 国内:pdai:JUC 锁——AbstractQueuedSynchronizer 详解:采用独占、共享与模板方法分工的说明,解释同一个同步框架怎样服务于不同资源规则,而不是把 state 一律理解成锁标志。
- 国外:Java SE 25:AbstractQueuedSynchronizer:核对状态操作、获取释放流程和公平性条件,说明 FIFO 队列为什么不自动保证公平获取。
- 国外:Java SE 25:AQS ConditionObject:核对 await 保存并释放状态、signal 转移等待者、返回前重新获取的规则,区分条件等待和锁获取。



