aqs独占锁机制通过acquire与release协作,结合子类实现的tryacquire/tryrelease完成“检查→排队→唤醒→更新”闭环;state控制资源数,exclusiveownerthread保障可重入与调试可见性。

AQS 的独占锁机制核心在于 acquire 和 release 方法的协作,配合 tryAcquire 与 tryRelease 的子类定制逻辑,形成“状态检查→排队阻塞→唤醒重试→状态更新”的闭环。它不直接实现锁语义,而是把资源竞争的骨架搭好,把关键决策权交给子类。
独占模式下的 acquire 流程
调用 acquire(int arg) 是获取独占锁的起点,其逻辑简洁但严谨:
- 先尝试一次
tryAcquire(arg):由子类(如ReentrantLock.NonfairSync或FairSync)实现,通常通过 CAS 修改state值完成抢占;成功则直接返回,不入队 - 失败后执行
addWaiter(Node.EXCLUSIVE):将当前线程封装为独占模式节点,以 CAS 方式插入同步队列尾部(tail) - 再调用
acquireQueued(node, arg):节点进入自旋等待——检查前驱是否为头节点且tryAcquire成功;否则设置前驱节点waitStatus = SIGNAL,然后调用LockSupport.park(this)阻塞自身 - 被唤醒后(例如前驱释放锁并调用
unparkSuccessor),继续循环尝试获取,直到成功才退出队列、设置自己为新 head
state 与 exclusiveOwnerThread 的双重保障
state 是 AQS 的原子状态变量,表示资源的持有数量(如可重入锁的重入次数);而 exclusiveOwnerThread 来自父类 AbstractOwnableSynchronizer,用于记录当前持有锁的线程引用。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
tryAcquire中不仅要判断state == 0(无锁),还要校验是否是同一线程重入(getExclusiveOwnerThread() == currentThread),再决定是 CAS 更新state还是仅递增 -
tryRelease同样需确保只有持有者才能释放,并在state归零时清空exclusiveOwnerThread - 二者缺一不可:
state控制并发许可数,exclusiveOwnerThread实现可重入和调试可见性(比如getOwner()可查谁持锁)
同步队列的关键节点行为
AQS 的同步队列是基于 CLH 的变体双向链表,每个 Node 承载一个等待线程及其状态。真正驱动调度的是节点间的协作关系:
- 头节点(
head)始终代表“正在占有锁”或“刚释放锁”的线程(不一定存活),它的存在让后续节点能快速判断是否轮到自己 - 当某节点成为 head 的后继时,若其
waitStatus == SIGNAL,说明它已被前驱标记为“待唤醒”,一旦前驱释放锁,就会触发unparkSuccessor唤醒它 -
CANCELLED状态节点会被跳过:若线程中断或超时取消等待,对应节点的waitStatus被设为1,后续入队或唤醒逻辑会主动绕过它,保证队列洁净
公平性差异体现在 tryAcquire 的时机
公平锁与非公平锁的区别不在 AQS 框架本身,而在于 tryAcquire 的实现策略:
- 非公平锁:直接 CAS 尝试抢锁,不管队列是否有等待者;即使有线程已在排队,新线程仍可能插队成功
- 公平锁:在 CAS 前增加判断 ——
!hasQueuedPredecessors(),即确认同步队列为空或当前节点是队首才允许抢锁,从而保证 FIFO 顺序 - 这种设计体现了 AQS 的解耦思想:框架管排队和唤醒,子类管“何时能抢”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










