可重入锁在 AQS 中如何实现?
可重入锁(ReentrantLock)在 AQS(AbstractQueuedSynchronizer)中的实现是 Java 并发编程中的核心机制之一。
下面从实际结构、可重入原理、核心方法、源码片段、内存语义等多个层面,深入剖析:
一、背景知识简述
什么是 AQS?
AQS,全称 AbstractQueuedSynchronizer,是 J.U.C(java.util.concurrent)包中的基础同步框架:
它基于一个 volatile 的 int 状态变量(
state)和一个 FIFO 队列,实现各种锁与同步器的基础,比如:
ReentrantLockCountDownLatchSemaphoreReentrantReadWriteLock
二、什么是可重入?
可重入(Reentrancy)是指:
同一线程可以重复获取同一把锁,不被阻塞。
如:
lock.lock(); // 第一次加锁
lock.lock(); // 第二次加锁:不阻塞
...
lock.unlock(); // 释放一次
lock.unlock(); // 真正释放
三、可重入锁的关键点(ReentrantLock 依赖 AQS)
| 关键点 | 实现细节 |
|---|---|
| 锁状态计数 | state 表示锁的持有状态(加锁次数) |
| 锁持有者记录 | exclusiveOwnerThread 表示当前持有锁的线程 |
| 可重入判断 | 如果当前线程再次获取锁,允许加锁、state++ |
| 解锁机制 | 每次 unlock(),state--,直到 state==0 才释放锁 |
四、源码深度解析:如何实现可重入
源码位置:
ReentrantLock.java(封装接口)AbstractQueuedSynchronizer.java(核心逻辑)
1. lock() 加锁逻辑:可重入判断
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
2. tryAcquire() 实现可重入逻辑
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 如果没人持有锁,尝试获取(用 CAS)
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) {
// 🔁 这里是“可重入”的关键!
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); // 增加持有次数
return true;
}
return false;
}
同一个线程再次进来,不再排队,直接累加
state。
3. unlock() 解锁逻辑:逐层释放
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
4. tryRelease():state–,只有为0才真正释放锁
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c); // 🔁 可重入对应的 state 次数
return free;
}
五、线程调度模型图解
Thread-A ── lock() → state=1
── lock() → state=2(可重入)
Thread-A ── unlock() → state=1
── unlock() → state=0 → 唤醒下一个线程
六、底层核心机制
| 机制 | 说明 |
|---|---|
| CAS | 比较并交换 state,原子更新状态 |
| volatile | state 是 volatile,确保多线程下的可见性 |
| 自旋队列 | AQS 中的等待线程用双向链表(CLH 队列)管理 |
| 内存语义 | acquire 和 release 封装了内存屏障 |
七、源码与参考资料
- 🔗 ReentrantLock 源码(GitHub – OpenJDK)
- 🔗 AQS 源码(GitHub)
- 📘 《Java 并发编程实战》:第 14 章
- 📘 《深入理解 Java 虚拟机》:线程安全和锁优化
总结一句话
AQS 中可重入锁通过:
state计数 + 当前线程判断 + CAS 原子操作 实现线程的多次加锁和对应解锁。
更多详细内容请关注其他相关文章!