reentrantlock 的可重入性由 aqs 的 state 计数器和 exclusiveownerthread 线程标识共同实现:state 记录同一线程的持有次数,exclusiveownerthread 确保仅该线程可重入和释放。

ReentrantLock 的可重入性不是靠魔法,而是靠 AQS(AbstractQueuedSynchronizer)中的 state 字段 + 线程身份识别 两个核心配合实现的。源码层面的关键逻辑集中在 Sync#nonfairTryAcquire 和 Sync#tryRelease 这两个钩子方法里。
state 计数器记录重入次数
AQS 的 state 是一个 volatile int,初始值为 0,代表锁空闲。它的含义不是“是否被占用”,而是“当前线程持有锁的次数”:
- 首次获取锁时:若
state == 0,通过 CAS 将其设为 1,并调用setExclusiveOwnerThread(current)记录持有线程; - 同一线程再次调用
lock():发现state > 0且getExclusiveOwnerThread() == current,就直接执行setState(state + 1); - 每次重入,
state就加 1;每次unlock(),state就减 1; - 只有当
state减到 0 时,才真正释放锁,同时清空exclusiveOwnerThread。
exclusiveOwnerThread 确保“只认自己人”
仅仅靠 state 不足以区分不同线程——必须绑定线程身份。AQS 提供了 exclusiveOwnerThread 字段(由 AbstractOwnableSynchronizer 定义),它在首次加锁和每次重入时都被设为当前线程。释放锁时只允许该线程操作,其他线程调用 unlock() 会抛出 IllegalMonitorStateException。
这个字段让 ReentrantLock 能精准判断:“是不是我上次锁的?还能不能再进一层?”而不是简单看锁有没有被占。
非公平与公平模式共享同一套重入逻辑
无论是 NonfairSync 还是 FairSync,它们重写的 tryAcquire 方法中,对“当前线程已持有锁”的判断逻辑完全一致:
- 先检查
state != 0; - 再检查
getExclusiveOwnerThread() == currentThread; - 满足则直接递增
state,跳过排队或竞争流程。
也就是说,公平性只影响“首次争抢锁”的排队规则,不影响重入行为本身。哪怕在公平锁下,已持有锁的线程再次进入,也无需排队,直接成功。
tryRelease 中的原子性校验
tryRelease(int releases) 方法负责释放锁,关键点在于:
- 先计算
nextc = getState() - releases(通常releases = 1); - 若
nextc == 0,说明这是最后一次释放,此时才调用setExclusiveOwnerThread(null)并返回true; - 若
nextc > 0,只更新setState(nextc),返回false,表示锁还被持有,上层不会唤醒等待队列中的线程。
这种设计保证了:释放动作必须与获取次数严格匹配,避免误释放或提前唤醒。
不复杂但容易忽略:可重入的本质,就是把“锁”从布尔开关升级成了带身份的计数器。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











