ReentrantLock加锁路径本质是AQS的acquire流程:先调用Sync.lock()选择公平/非公平实现,再进入AQS.acquire(1),执行tryAcquire尝试获取,失败则acquireQueued入队自旋等待,最终park挂起。

ReentrantLock 的加锁路径本质是 AQS(AbstractQueuedSynchronizer)的 acquire 流程,核心在 lock() 调用后进入 AQS 的独占式获取逻辑。下面从源码层级逐层追踪完整路径,聚焦关键方法、状态流转和关键判断点,不展开无关细节。
1. ReentrantLock.lock() → Sync.lock() 选择公平/非公平实现
ReentrantLock 是一个门面类,内部持有静态抽象类 Sync 的子类实例(NonfairSync 或 FairSync)。调用 lock() 实际委托给具体 Sync 实现:
-
NonfairSync.lock():先尝试 CAS 抢占锁(compareAndSetState(0, 1)),成功则设置 owner 为当前线程;失败才走 AQS 公共流程。 -
FairSync.lock():直接跳过抢占,无条件走acquire(1),保证 FIFO 公平性。
2. 进入 AQS.acquire(int arg) —— 核心入口
无论公平与否,最终都会进入 AbstractQueuedSynchronizer.acquire(1)(arg=1 表示独占模式申请一个单位):
- 先调用
tryAcquire(arg):由子类(即Sync)实现,决定是否能立即获得锁; - 若返回
true,整个加锁完成; - 若返回
false,执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg),开始排队等待。
3. tryAcquire(arg) 在 NonfairSync/FairSync 中的具体逻辑
这是锁语义的关键差异点,源码位于 ReentrantLock.java 内部类中:
- NonfairSync.tryAcquire: ① 若 state == 0,直接 CAS 尝试获取(体现“非公平”); ② 若 state > 0 且当前线程是 owner,则 state++(可重入); ③ 否则返回 false。
-
FairSync.tryAcquire:
① 必须先检查
!hasQueuedPredecessors()(即队列为空或当前节点是头结点后第一个)才允许尝试 CAS; ② 其余同上(state==0 时 CAS,或可重入)。
注意:hasQueuedPredecessors() 是公平性的核心判断,通过读取 AQS 队列 head/tail 和前驱节点状态实现,不依赖 synchronized。
4. acquireQueued(addWaiter(...), arg) —— 入队与自旋等待
当 tryAcquire 失败后,走标准排队流程:
-
addWaiter(Node.EXCLUSIVE):创建新 Node(thread=current, mode=EXCLUSIVE),CAS 插入同步队列尾部;失败则退化为循环 CAS 直到成功。 -
acquireQueued(final Node node, int arg): ① 自旋中反复调用shouldParkAfterFailedAcquire(pred, node)判断是否该挂起; ② 若前驱节点 status == -1(SIGNAL),则调用parkAndCheckInterrupt()阻塞当前线程; ③ 被唤醒后再次尝试tryAcquire,成功则将 node 设为 head 并返回;失败则继续循环。
注意:挂起前会把前驱节点的 waitStatus 设为 SIGNAL(-1),确保释放锁时能唤醒后继节点。
LockSupport.park() 挂起,直到被前驱节点在 unparkSuccessor() 中唤醒,再重新竞争 state —— 这就是 ReentrantLock 加锁的完整闭环。Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











