👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中... 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
📚欢迎订阅专栏,专栏名《在2B工作中寻求并发是否搞错了什么》
因为本文说的是ReentrantLock源码,因此会默认,大家对AQS有基本的了解(比如同步队列、条件队列大概> 长啥样?)。不懂AQS的小朋友们,你们好呀!也欢迎先看看这篇
【源码】【Java并发】【AQS】从ReentrantLock、Semaphore、CutDownLunch、CyclicBarrier看AQS源码
基本结构分析
Sync抽象类

ReentrantLock
的内部抽象类,继承自AQS
。
Sync
支持了锁的可重入、锁的释放、提供了获取ConditinObject
(可以将线程阻塞唤醒)。
咱们这里就重点说下锁的获取和释放:
定义锁的释放逻辑 :实现 tryRelease()
方法,通过state
变量记录重入次数(释放时递减)。
具体获取锁的逻辑: 定义lock
抽象方法,需要子类FairSync
和NonfairSync
实现。

独占锁实现
这里要说ReentrantLock
下锁的实现,是基于AQS
的state
字段实现的。
java
/**
* The synchronization state.
*/
private volatile int state;
ReentrantLock的state,值为0表示没有线程占有锁,值为1表示这个锁已经被占有。
获取锁 :ReentrantLock
会尝试通cas
将state
从0改为1,就是获取锁成功的意思。下面以非公平获取,nonfairTryAcquire
实现为例子:
java
// ReentrantLock.Sync#nonfairTryAcquire
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// state为0表示没有线程占有锁,我们当前线程可以尝试占有
if (c == 0) {
// cas将state由0改为1
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 锁的可重入的逻辑:如果现在持有锁的线程,是当前锁的话,state++
else if (current == getExclusiveOwnerThread()) {
// state++
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
释放锁 :因为有锁的重入的情况(锁的重入会导致state++
),释放锁是将state--
(而不是将state
从1改为0),减到state
为0就表示锁已经被释放。
java
// ReentrantLock.Sync#tryRelease
// ReentrantLock实现中,releases是1
protected final boolean tryRelease(int releases) {
int c = getState() - releases; // 将state减1
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 减少后state变为0,说明锁可以释放了
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c); // 修改state数量
return free;
}
protected final void setState(int newState) {
state = newState;
}
// === 下面证明为啥tryRelease方法的入参releases是1 ===
// ReentrantLock#unlock
// 释放锁
public void unlock() {
// 调用到AQS的release方法
sync.release(1);
}
// AbstractQueuedSynchronizer#release
// arg的值就是1
public final boolean release(int arg) {
// 调用子类(ReentrantLock.Sync)实现tryRelease方法,arg传的是1。
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
普通lock方法
java
// ReentrantLock#lock
public void lock() {
sync.lock();
}
公平和非公平的实现,我们可以看到,区别就在,非公平的实现,多了先,尝试先获取锁了下。
java
// ReentrantLock.NonfairSync#lock
final void lock() {
acquire(1);
}
// ReentrantLock.FairSync#lock
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
acquire
方法,这里我们重点看子类的具体实现tryAcquire
方法。
java
// AbstractQueuedSynchronizer#acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 调用子类具体实现的tryAcquire方法
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
非公平的实现tryAcquire
java
// ReentrantLock.NonfairSync#tryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// ReentrantLock.Sync#nonfairTryAcquire
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 当前没有线程占有锁,尝试cas获取锁。
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 可重入锁,state++。
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
公平的实现tryAcquire
方法
java
// ReentrantLock.FairSync#tryAcquire
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 当前没有线程占有锁,获取锁
if (c == 0) {
// 和非公平多了一个判断hasQueuedPredecessors
// 判断当前线程是否需要排队(即检查同步队列中是否有其他线程比它更早申请锁)。
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 可重入锁,state++
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
深入AQS源码,看hasQueuedPredecessors
, 判断当前线程是否需要排队。
不懂AQS同步队列的小朋友,你们有难了!嘿嘿,如果不懂AQS的,建议先了解下AQS。(疑似主播二次广告植入)
【源码】【Java并发】【AQS】从ReentrantLock、Semaphore、CutDownLunch、CyclicBarrier看AQS源码
什么样的情况不用排队?同步队列中,下一个Node是当前线程的情况:

java
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
线程中断概念
中断相关知识补充,如果你已经知道中断相关的知识,可以跳过。
稍后,你可能会看到这个方法Thread.interrupted()
,你一定会好奇,芝士什么意思勒?它有什么用?
arduino
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted(); // Thread.interrupted()????
}
那聪明的你,一定要知道,什么是中断?这里主播会简单介绍下的:
Java 的线程中断(Thread Interruption) 是一种协作式机制,用于通知线程"有人希望它停止当前的操作",但线程是否停止、何时停止以及如何停止,完全由线程自身决定。中断机制的核心是通过标志位传递信号,而不是强制终止线程。
是用来替代Tread.stop()这种不安全的方法的。
简单案例1:
java
Thread worker = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) { // 检查中断标志
// 执行任务逻辑
System.out.println("Working...");
}
System.out.println("Thread gracefully stopped.");
});
worker.start();
// 外部请求中断
worker.interrupt();
简单案例2:处理阻塞的中断
java
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
while (true) {
System.out.println("线程即将进入阻塞...");
Thread.sleep(1000); // 模拟阻塞操作
}
} catch (InterruptedException e) {
System.out.println("线程在阻塞时被中断,捕获异常!");
Thread.currentThread().interrupt(); // 重新设置中断标志
}
});
thread.start();
Thread.sleep(10);
thread.interrupt(); // 中断阻塞中的线程
}
ok呀,聪明的你一定对线程中断有一定的了解了,下面是下Thread的一些关于线程中断的方法:
interrupt()
:设置线程的中断标志位,即使线程正在阻塞状态(如sleep),也会触发InterruptedException
。isInterrupted()
:检查线程的中断标志位(不清除标志位)。Thread.interrupted()
:检查当前线程的中断标志位,并清除标志位(静态方法)。
现在,你看懂这个方法了吗?
java
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted(); // 返回当前线程是否被中断,并清除标志位
}
可中断lock
其实和普通的lock是差不多的,多了对线程是否发生中断的判断,如果发生中断的话,就抛出中断异常。
java
// ReentrantLock#lockInterruptibly
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
acquireInterruptibly方法,多了对中断的判断。
java
// AbstractQueuedSynchronizer#acquireInterruptibly
public final void acquireInterruptibly(int arg)
throws InterruptedException {
// 判断当前线程是否被中断,如果被中断,就抛出中断异常
if (Thread.interrupted())
throw new InterruptedException();
// tryAcquire子类具体实现,上面普通lock说过了。
if (!tryAcquire(arg))
doAcquireInterruptibly(arg); // 👈这里重点看看AQS是怎么做的。
}
doAcquireInterruptibly方法,shouldParkAfterFailedAcquire
方法和parkAndCheckInterrupt
为true的话,就抛出中断异常。
java
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
return;
}
// 当parkAndCheckInterrupt也返回为true的话,就抛出中断异常
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
// parkAndCheckInterrupt方法
private final boolean parkAndCheckInterrupt() {
// 挂起线程
LockSupport.park(this);
// 线程恢复后,返回该线程是否被中断,并将标志位重置
return Thread.interrupted();
}
对比普通lock的acquireQueued
的只是记录下发生了线程中断,然后再自我中断(因为标志位被重置为false了)。而doAcquireInterruptibly
是直接抛出异常。
java
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true; // 这里记录下线程发生了中断
}
} finally {
if (failed)
cancelAcquire(node);
}
}
// acquireQueued返回为true会发生什么? ---> 自我中断
public final void acquire(int arg) {
// 如果获取锁失败 且 acquireQueued时,线程发生了中断
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt(); // 自我中断
}
// 自我中断 (因为标志位,在acquireQueued时,被重置为fasle了)
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
超时lock
超时lock入口,tryLock方法:
java
// ReentrantLock#tryLock
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
tryAcquireNanos
方法,上面的文章说过了子类的实现tryAcquire
方法,这里重点看AQS是怎么实现doAcquireNanos
方法。
java
// AbstractQueuedSynchronizer#tryAcquireNanos
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
// 同中断的lock,发生中断,直接抛中断异常
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout); // 重点看AQS的doAcquireNanos实现
}
doAcquireNanos
方法,
java
// AbstractQueuedSynchronizer#doAcquireNanos
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
// 计算截止时间
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
// 超时返回false
if (nanosTimeout <= 0L)
return false;
// spinForTimeoutThreshold是1000L,如果挂起的太短就不挂起了,影响性能
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout); // 挂起线程
// 发生了中断的话,就抛出中断异常
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
🤔我们可以看到,和中断的lock相比,这里多了时间的计算,和挂起线程一段时间。
锁释lock
方法入口unlock:
java
// ReentrantLock#unlock
public void unlock() {
sync.release(1);
}
调用AQS的release方法,这里重点看子类的实现tryRelease
方法。
java
// AbstractQueuedSynchronizer#release
public final boolean release(int arg) {
// 调用子类实现的tryRelease方法,返回true,就唤醒别的线程去抢锁。
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
子类Sync
实现tryRelease
方法:
java
// ReentrantLock.Sync#tryRelease
protected final boolean tryRelease(int releases) {
// 将state--
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// state为0,说明没有线程占有锁
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
// 更新state数量
setState(c);
return free;
}
线程间通信实现源码
我们的ReentrantLock直接使用了AQS提供的线程通信,下面再分析下去,就是在分析AQS了。
先来个简单的用法,热热身体吧!
java
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
lock.lock();
condition.await();
System.out.println("sub thread:" + Thread.currentThread() + " get lock");
} catch (InterruptedException e) {
System.out.println("sub thread interrupted");
} finally {
lock.unlock();
}
}).start();
}
Thread.sleep(1000);
lock.lock();
try {
System.out.println("main thread singleAll");
condition.signalAll();
} finally {
lock.unlock();
}
}
输出结果
shell
main thread singleAll
sub thread:Thread[Thread-0,5,main] get lock
sub thread:Thread[Thread-1,5,main] get lock
sub thread:Thread[Thread-2,5,main] get lock
sub thread:Thread[Thread-3,5,main] get lock
sub thread:Thread[Thread-4,5,main] get lock
Conditon接口
java
public interface Condition {
// ======== 等待相关 ===========
void await() throws InterruptedException; // 等待直到被通知或中断
void awaitUninterruptibly(); // 不可中断的等待
long awaitNanos(long nanosTimeout) throws InterruptedException; // 纳秒级超时等待
boolean await(long time, TimeUnit unit) throws InterruptedException; // 带时间单位的超时等待
boolean awaitUntil(Date deadline) throws InterruptedException; // 等待到指定时间点
// ======== 通知相关 ===========
void signal(); // 唤醒一个等待线程
void signalAll(); // 唤醒所有等待线程
}
AQS中的ConditionObject实现

ReentrantLock是只是获取了这个ConditionObject
java
// java.util.concurrent.locks.ReentrantLock.Sync#newCondition
final ConditionObject newCondition() {
return new ConditionObject();
}
awat方法
await方法
java
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter(); // 向条件队列新增Node
int savedState = fullyRelease(node); // 释放锁,savedState是释放锁之前,state数值,1
int interruptMode = 0;
// 判断是否在同步队列中,不在就挂起线程。
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
// 1.发生中断退出循环 2.给interruptMode赋值 THROW_IE(-1) signal发生前, REINTERRUPT(1) signal发生后
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 抢占锁发生中断(acquireQueued方法返回是否发生中断)
// ============且=============
// 中断原中断模式不是 THROW_IE,将模式改为 REINTERRUPT(避免覆盖原有的中断语义)
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
// 清除无效节点
if (node.nextWaiter != null)
unlinkCancelledWaiters();
// 处理中断结果
// THROW_IE:抛出 InterruptedException,通知调用者等待被中断。
// REINTERRUPT:重新标记线程的中断状态(调用 Thread.currentThread().interrupt()),但不抛出异常。
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
addConditionWaiter方法:向条件队列中新增一个Node。
java
// AbstractQueuedSynchronizer.ConditionObject#addConditionWaiter
private Node addConditionWaiter() {
Node t = lastWaiter;
// 清除为CANCEL状态的尾部Node
if (t != null && t.waitStatus != Node.CONDITION) {
// 从firstWaiter开始,向后删除waitStatus为Node.CONDITION的Node
unlinkCancelledWaiters();
t = lastWaiter;
}
// 新增1个waitStatus为Node.CONDITION的Node
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
fullyRelease方法:释放锁资源
java
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();
// 释放锁
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
isOnSyncQueue方法:判断是否在同步队列中
java
final boolean isOnSyncQueue(Node node) {
// 不在同步队列中:Node等待状态为Node.CONDITION 或 Node.next为空(新增Node,条件队列不用prev这个字段,同步队列这个prev字段不可能为空)
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// 如果有Node.next != null,那就是在同步队列中(因为条件队的下一个Node,用的是Node的nextWaiter字段)
if (node.next != null)
return true;
// 节点可能已设置前驱指针,但尚未真正入同步队列(因CAS操作可能失败)
// 从后向前找,找到就返回true,没有就返回fasle
return findNodeFromTail(node);
}
findNodeFromTail方法
java
private boolean findNodeFromTail(Node node) {
Node t = tail;
// 从后向前找新增Node,找到就返回true,没有就返回fasle
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
checkInterruptWhileWaiting:判断是等待前中断,还是等待后中断
java
// 检查线程在条件队列(Condition Queue)中等待时是否被中断
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ? // 检查并清除中断状态
(transferAfterCancelledWait(node) ? // 如果中断发生,尝试转移节点到同步队列
THROW_IE : // 中断在 signal 前:需抛出中断异常
REINTERRUPT) : // 中断在 signal 后:需重设中断状态
0; // 未发生中断,返回0
}
private static final int THROW_IE = -1;
private static final int REINTERRUPT = 1;
transferAfterCancelledWait
java
final boolean transferAfterCancelledWait(Node node) {
// CAS将Node的等待状态改为0,加入同步队列
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true; // 中断发生在single前
}
// 如果 CAS 失败,循环检查节点是否已被其他线程加入同步队列
// CAS失败说明,其他线程正在转移节点,必须通过 while (!isOnSyncQueue(node)) 等待其完成
// Thread.yield()是为了在 "自旋等待其他线程完成操作" 时,平衡 CPU 资源消耗与等待效率,避免忙等待的极端性能损耗。
while (!isOnSyncQueue(node))
Thread.yield();
return false; // 中断发生在single后
}
reportInterruptAfterWait:根据interruptMode对中断进行不同的处理
java
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
// 中断在 signal 前:需抛出中断异常
if (interruptMode == THROW_IE)
throw new InterruptedException();
// 中断在 signal 后:需重设中断状态
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
signal方法
就是唤醒条件队列第一个有效节点。
java
public final void signal() {
// 判断是不是当前线程持有锁
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
// 条件队列中有节点,则执行具体唤醒逻辑
if (first != null)
doSignal(first);
}
doSignal,遍历条件队列,找到第一个未被取消的节点,并将其转移到同步队列以唤醒对应线程。
java
private void doSignal(Node first) {
do {
// 更新条件队列头节点,并断开当前节点的链接(其实就是移除条件队列)
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
// 尝试将当前节点转移到同步队列
} while (!transferForSignal(first) && // 若转移失败,继续尝试下一个节点
(first = firstWaiter) != null); // 更新 first 为下一个节点,直到队列为空
}
将节点由条件队列转同步队列
java
final boolean transferForSignal(Node node) {
// CAS修改当前节点等待状态,由Node.CONDITION(-2)修改为0
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 当前节点进入同步队列中
Node p = enq(node);
int ws = p.waitStatus;
// 唤醒线程:等待状态为CANCELLED(1)或者 CAS修改等待状态到Node.SIGNAL(-1)
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
signalAll方法
让我们看看signalAll和signal的区别有哪里不同吧!
方法入口:
signalAll方法,这里和signal差不多嘛,那要我们看看具体的doSignalAll有什么区别了。
java
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
doSignalAll方法,遍历条件队列,只要Node不为null,就唤醒。
java
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
// 转为同步队列
transferForSignal(first);
first = next;
} while (first != null);
}
后话
本篇,从ReentrantLock的两大功能独占锁
和线程通信
的源码角度来看ReentrantLock
。
聪明的你一定学会了很多吧( ̄▽ ̄)"