当前位置: 首页 > news >正文

JUC学习笔记-----ReentrantLock

目录

ReentrantLock原理

1. 非公平锁实现原理

加锁成功流程

加锁失败流程

解锁竞争成功流程

解锁竞争失败流程

可重入原理

可打断模式

不可打断模式

可打断模式

公平锁实现原理

条件变量实现原理

await流程

signal流程


ReentrantLock原理

1. 非公平锁实现原理

加锁成功流程

先从构造器开始看,默认为非公平锁实现

public ReentrantLock() {sync = new NonfairSync();
}

NonfairSync 继承自 AQS

没有竞争时

如果 CAS 成功,说明当前线程抢占锁成功,设置当前线程为独占锁的拥有者

// 非公平锁的实现类,继承自 Sync(Sync 是 ReentrantLock 内部的抽象同步器)
static final class NonfairSync extends Sync {// 序列化版本号,用于 Java 序列化机制private static final long serialVersionUID = 7316153563782823691L;// 注释说明:执行加锁操作。先尝试直接抢占锁(不排队),抢占失败后回退到正常的锁获取流程final void lock() {// CAS 操作:尝试将同步状态(state)从 0(未锁定)更新为 1(已锁定)// state 是 AQS(AbstractQueuedSynchronizer)中的核心变量,用于表示锁的状态if (compareAndSetState(0, 1))// 如果 CAS 成功,说明当前线程抢占锁成功,设置当前线程为独占锁的拥有者setExclusiveOwnerThread(Thread.currentThread());else// 如果 CAS 失败,调用 AQS 的 acquire 方法,进入正常的锁获取流程(排队、自旋等)// 参数 1 表示当前线程尝试获取 1 把锁(可重入锁的计数逻辑)acquire(1);}// 尝试获取锁的具体实现,重写 AQS 的 tryAcquire 方法// acquires 参数表示当前线程尝试获取的锁数量(对于 ReentrantLock 是 1,支持可重入时会累加)protected final boolean tryAcquire(int acquires) {// 调用非公平锁的 tryAcquire 实现,核心逻辑在 nonfairTryAcquire 中return nonfairTryAcquire(acquires);}
}

加锁失败流程

第一个竞争出现时

1. CAS 尝试将 state 由 0 改为 1,结果失败

2. 进入 tryAcquire 逻辑,这时 state 已经是1,结果仍然失败的

public final void acquire(int arg) {// 1. 尝试获取锁:调用 tryAcquire 方法(由子类实现,比如 ReentrantLock 的 Sync 类)//    如果 tryAcquire 返回 true,说明获取锁成功,直接返回,不进入后续逻辑//    如果返回 false,说明获取锁失败,进入排队流程if (!tryAcquire(arg) && // 2. 获取锁失败后,执行的逻辑://    a. addWaiter(Node.EXCLUSIVE):将当前线程封装成 Node,加入等待队列尾部//    b. acquireQueued(...):让 Node 在队列中自旋/挂起,等待获取锁的机会//    c. 整个 acquireQueued(...) 返回 true 表示当前线程在等待过程中被中断acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 3. 如果 acquireQueued 返回 true(即线程在等待中被中断),执行自我中断selfInterrupt();
}

3. 接下来进入 addWaiter 逻辑,构造 Node 队列

图中黄色三角表示该 Node 的 waitStatus 状态,其中 0 为默认正常状态

Node 的创建是懒惰的

其中第一个 Node 称为 Dummy(哑元)或哨兵,用来占位,并不关联线程

当前线程进入 acquireQueued 逻辑

// 方法作用:让节点在 AQS 队列中自旋/挂起,直到获取锁或被中断
// node:当前线程对应的等待队列节点
// arg:获取锁的参数(ReentrantLock 中通常为 1,代表获取 1 把锁)
final boolean acquireQueued(final Node node, int arg) {// 标记是否获取锁失败(用于 finally 中取消节点)boolean failed = true;try {// 标记线程是否在等待过程中被中断boolean interrupted = false;// 自旋:不断尝试获取锁,直到成功或被中断for (;;) {// 1. 获取当前节点的前驱节点final Node p = node.predecessor();// 2. 如果前驱是头节点,尝试获取锁if (p == head && tryAcquire(arg)) {// 2.1 成功获取锁:将当前节点设为新的头节点setHead(node);// 2.2 断开前驱节点的 next 引用,帮助 GC 回收p.next = null; // 2.3 标记获取锁成功,后续不再执行 cancelAcquirefailed = false;// 2.4 返回中断状态(false 表示未被中断)return interrupted;}// 3. 获取锁失败:判断是否需要挂起当前线程if (shouldParkAfterFailedAcquire(p, node) &&// 3.1 挂起线程,并检查是否被中断parkAndCheckInterrupt()) // 3.2 如果被中断,标记 interrupted 为 trueinterrupted = true;}} finally {// 4. 如果获取锁失败(failed 仍为 true),取消当前节点在队列中的等待if (failed)cancelAcquire(node);}
}

1. acquireQueued 会在一个死循环中不断尝试获得锁,失败后进入 park 阻塞

2. 如果自己是紧邻着 head(排第二位),那么再次 tryAcquire 尝试获取锁,当然这时 state 仍为 1,失败

3. 进入 shouldParkAfterFailedAcquire 逻辑,将前驱 node,即 head 的 waitStatus 改为 -1(有职责去唤醒它的后继结点),这次返回 false

4. shouldParkAfterFailedAcquire 执行完毕回到 acquireQueued ,再次 tryAcquire 尝试获取锁,当然这时 state 仍为 1,失败

5. 当再次进入 shouldParkAfterFailedAcquire 时,这时因为其前驱 node 的 waitStatus 已经是 -1,这次返回 true

6. 进入 parkAndCheckInterrupt, Thread-1 park(灰色表示)

// parkAndCheckInterrupt 方法:挂起当前线程,并检查线程是否被中断
private final boolean parkAndCheckInterrupt() {// 1. 挂起当前线程// LockSupport.park(this):将当前线程挂起,直到被 unpark 或被中断// 参数 this(Node 实例)是“ blocker”,用于线程 Dump 时显示更友好的调试信息(关联到 AQS 队列节点)LockSupport.park(this);// 2. 线程被唤醒后,检查当前线程的中断状态// Thread.interrupted():返回当前线程的中断状态,并清除中断标记return Thread.interrupted();
}

再次有多个线程经历上述过程竞争失败,变成这个样子

Thread-0 释放锁,进入 tryRelease 流程

// tryRelease 方法:尝试释放锁
// releases:释放的锁数量(ReentrantLock 中通常为 1,代表释放 1 把锁)
protected final boolean tryRelease(int releases) {// 1. 计算释放后的 state 值// getState():获取 AQS 中表示锁状态的变量(state)// c = 原 state 值 - 释放的数量(releases)int c = getState() - releases;// 2. 检查当前线程是否是锁的持有者// getExclusiveOwnerThread():获取当前持有锁的线程// 如果当前线程不是持有者,抛出异常(保证锁的释放逻辑正确)if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();// 3. 标记锁是否完全释放(state == 0)boolean free = false;// 如果释放后 state == 0,说明锁完全释放if (c == 0) {free = true;// 清除锁的持有者(标记为 null)setExclusiveOwnerThread(null);}// 4. 更新 state 的值(可能是部分释放,比如可重入锁的重入次数减 1)setState(c);// 5. 返回是否完全释放锁(free 为 true 表示完全释放)return free;
}
解锁竞争成功流程

设置 exclusiveOwnerThread 为 null

state = 0

当前队列不为 null,并且 head 的 waitStatus = -1,进入 unparkSuccessor 流程

// release 方法:释放锁的核心逻辑
public final boolean release(int arg) {// 1. 尝试释放锁(由子类实现,比如 ReentrantLock 的 tryRelease)if (tryRelease(arg)) {// 2. 如果释放成功,获取队列的头节点Node h = head;// 3. 检查头节点是否有效(非空)且头节点的等待状态不是 0//    waitStatus == 0:初始状态;>0:已取消;<0:需要唤醒(如 SIGNAL)if (h != null && h.waitStatus != 0)// 4. 唤醒头节点的后继节点(让后继线程尝试获取锁)unparkSuccessor(h);return true;}// 如果释放锁失败(tryRelease 返回 false),返回 falsereturn false;
}
private void unparkSuccessor(Node node) {// 注释说明:如果节点状态为负数(可能需要唤醒),尝试清除状态(提前置为 0)// 即使清除失败或状态被其他线程修改,也不影响后续逻辑int ws = node.waitStatus;if (ws < 0)// CAS 操作:将节点的 waitStatus 从 ws 改为 0// 作用:清理节点状态,避免重复唤醒compareAndSetWaitStatus(node, ws, 0);// 注释说明:需要唤醒的线程保存在后继节点中,通常是直接取 node.next// 但如果后继节点为 null 或已取消(waitStatus > 0),则从队列尾部向前遍历,找到第一个未取消的后继节点Node s = node.next;// 如果后继节点为 null,或后继节点的 waitStatus > 0(已取消)if (s == null || s.waitStatus > 0) {s = null;// 从队列尾部(tail)向前遍历,找到最前面的未取消节点(waitStatus <= 0)for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0)s = t;}// 如果找到有效的后继节点,唤醒它if (s != null)LockSupport.unpark(s.thread);
}

找到队列中离 head 最近的一个 Node(没取消的),unpark 恢复其运行,本例中即为 Thread-1

回到 Thread-1 的 acquireQueued 流程

// 方法作用:让节点在 AQS 队列中自旋/挂起,直到获取锁或被中断
// node:当前线程对应的等待队列节点
// arg:获取锁的参数(ReentrantLock 中通常为 1,代表获取 1 把锁)
final boolean acquireQueued(final Node node, int arg) {// 标记是否获取锁失败(用于 finally 中取消节点)boolean failed = true;try {// 标记线程是否在等待过程中被中断boolean interrupted = false;// 自旋:不断尝试获取锁,直到成功或被中断for (;;) {// 1. 获取当前节点的前驱节点final Node p = node.predecessor();// 2. 如果前驱是头节点,尝试获取锁if (p == head && tryAcquire(arg)) {// 2.1 成功获取锁:将当前节点设为新的头节点setHead(node);// 2.2 断开前驱节点的 next 引用,帮助 GC 回收p.next = null; // 2.3 标记获取锁成功,后续不再执行 cancelAcquirefailed = false;// 2.4 返回中断状态(false 表示未被中断)return interrupted;}// 3. 获取锁失败:判断是否需要挂起当前线程if (shouldParkAfterFailedAcquire(p, node) &&// 3.1 挂起线程,并检查是否被中断parkAndCheckInterrupt()) // 3.2 如果被中断,标记 interrupted 为 trueinterrupted = true;}} finally {// 4. 如果获取锁失败(failed 仍为 true),取消当前节点在队列中的等待if (failed)cancelAcquire(node);}
}

解锁竞争失败流程

如果加锁成功(没有竞争),会设置

exclusiveOwnerThread 为 Thread-1,state = 1

head 指向刚刚 Thread-1 所在的 Node,该 Node 清空 Thread

原本的 head 因为从链表断开,而可被垃圾回收

如果这时候有其它线程来竞争(非公平的体现),例如这时有 Thread-4 来了

如果不巧又被 Thread-4 占了先

Thread-4 被设置为 exclusiveOwnerThread,state = 1

Thread-1 再次进入 acquireQueued 流程,获取锁失败,重新进入 park 阻塞

可重入原理

当同一线程调用两次nonfairTryAcquire

static final class NonfairSync extends Sync {// ...(其他代码)// 非公平锁的 tryAcquire 实现(Sync 继承自 AQS)// acquires:获取锁的次数(ReentrantLock 中通常为 1)final boolean nonfairTryAcquire(int acquires) {// 1. 获取当前线程final Thread current = Thread.currentThread();// 2. 获取 AQS 的 state(表示锁的状态,0 为未占用)int c = getState();// 3. 如果 state == 0(锁未被占用)if (c == 0) {// 3.1 尝试用 CAS 抢占锁(非公平性体现:不管队列,直接抢占)if (compareAndSetState(0, acquires)) {// 3.2 抢占成功:标记当前线程为锁的持有者setExclusiveOwnerThread(current);return true;}}// 4. 如果 state != 0(锁已被占用),检查是否是当前线程持有(可重入逻辑)else if (current == getExclusiveOwnerThread()) {// 4.1 计算重入后的 state(state += acquires)int nextc = c + acquires;// 4.2 防止溢出(理论上不会发生,除非恶意调用)if (nextc < 0) throw new Error("Maximum lock count exceeded");// 4.3 更新 state(可重入次数 +1)setState(nextc);return true;}// 5. 抢占失败且不可重入,返回 falsereturn false;}// 释放锁的实现(Sync 继承自 AQS)// releases:释放锁的次数(通常为 1)protected final boolean tryRelease(int releases) {// 1. 计算释放后的 state(state -= releases)int c = getState() - releases;// 2. 检查当前线程是否是锁的持有者(防止非法释放)if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();// 3. 标记是否完全释放锁(state == 0)boolean free = false;if (c == 0) {free = true;// 3.1 完全释放:清除锁的持有者setExclusiveOwnerThread(null);}// 4. 更新 state(可能是部分释放,如可重入次数减 1)setState(c);// 5. 返回是否完全释放锁return free;}
}
可打断模式
不可打断模式

线程在 acquireQueued 中自旋尝试获取锁时,若被中断,不会立即退出队列,而是继续自旋竞争锁。中断标记会被临时清除,仅在成功获取锁后,才通过 acquire 方法的 selfInterrupt 重新触发中断,保证业务逻辑能感知到中断事件,同时不影响锁竞争流程。

// Sync 继承自 AQS(AbstractQueuedSynchronizer),作为同步器基础
static final class NonfairSync extends Sync {// ...(其他已有逻辑)// parkAndCheckInterrupt:挂起线程并检查中断状态private final boolean parkAndCheckInterrupt() {// LockSupport.park(this):挂起当前线程,需通过 unpark 或中断唤醒// 参数 this(Node 实例)用于调试,线程 Dump 时显示关联的 AQS 队列节点LockSupport.park(this);// Thread.interrupted():返回当前线程中断状态,并清除中断标记return Thread.interrupted();}// acquireQueued:在 AQS 队列中自旋尝试获取锁,处理中断逻辑(不可打断模式核心)final boolean acquireQueued(final Node node, int arg) {// failed:标记锁获取是否失败,失败时需取消节点等待boolean failed = true;try {// interrupted:记录线程在等待过程中是否被中断boolean interrupted = false;// 自旋循环,持续尝试获取锁for (;;) {// 获取当前节点的前驱节点final Node p = node.predecessor();// 若前驱是头节点,尝试获取锁(tryAcquire 为 AQS 抽象方法,由子类实现)if (p == head && tryAcquire(arg)) {// 成功获取锁,将当前节点设为新头节点setHead(node);// 断开前驱节点引用,协助 GCp.next = null;// 标记获取锁成功,后续 finally 不执行 cancelAcquirefailed = false;// 返回中断状态(需获取锁后才反馈中断)return interrupted;}// 若获取锁失败,判断是否需要挂起线程,并处理中断if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt()) {// 若因中断唤醒,标记 interrupted 为 trueinterrupted = true;}}} finally {// 若获取锁失败(failed 仍为 true),取消当前节点的等待状态if (failed) {cancelAcquire(node);}}}// acquire:AQS 对外的获取锁入口方法public final void acquire(int arg) {// 尝试获取锁,若失败则入队并进入 acquireQueued 自旋if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {// 若 acquireQueued 返回 true(线程在等待中被中断),补充中断标记selfInterrupt();}}// selfInterrupt:重新触发当前线程中断(因 acquireQueued 清除了中断标记)static void selfInterrupt() {Thread.currentThread().interrupt();}
}
可打断模式
static final class NonfairSync extends Sync {// 可中断的锁获取方法// arg:获取锁的参数(通常为 1)public final void acquireInterruptibly(int arg) throws InterruptedException {// 检查当前线程是否已中断if (Thread.interrupted())// 若已中断,抛出 InterruptedExceptionthrow new InterruptedException();// 尝试获取锁if (!tryAcquire(arg))// 若获取失败,进入可中断的队列获取逻辑doAcquireInterruptibly(arg);}// 可中断的队列获取锁逻辑// arg:获取锁的参数(通常为 1)private void doAcquireInterruptibly(int arg) throws InterruptedException {// 将当前线程封装为 Node,加入 AQS 等待队列final Node node = addWaiter(Node.EXCLUSIVE);// 标记是否获取锁失败boolean failed = true;try {// 自旋尝试获取锁for (;;) {// 获取当前节点的前驱节点final Node p = node.predecessor();// 如果前驱是头节点,尝试获取锁if (p == head && tryAcquire(arg)) {// 成功获取锁,将当前节点设为新的头节点setHead(node);// 断开前驱节点的 next 引用,帮助 GC 回收p.next = null; // 标记获取锁成功failed = false;// 退出方法return;}// 如果获取锁失败,判断是否需要挂起线程if (shouldParkAfterFailedAcquire(p, node) &&// 挂起线程,并检查是否被中断parkAndCheckInterrupt()) {// 若被中断,抛出 InterruptedExceptionthrow new InterruptedException();}}} finally {// 如果获取锁失败(failed 为 true),取消当前节点的等待if (failed)cancelAcquire(node);}}
}
公平锁实现原理
static final class FairSync extends Sync {// 序列化版本号private static final long serialVersionUID = -3000897897090466540L;// 公平锁的获取锁方法final void lock() {acquire(1);}// AQS 继承的方法,尝试获取锁(公平锁实现)protected final boolean tryAcquire(int acquires) {// 获取当前线程final Thread current = Thread.currentThread();// 获取 AQS 的 state(表示锁的状态)int c = getState();// 如果 state == 0(锁未被占用)if (c == 0) {// 检查队列中是否有等待的节点if (!hasQueuedPredecessors() &&// CAS 尝试获取锁compareAndSetState(0, acquires)) {// 成功获取锁,设置当前线程为锁的持有者setExclusiveOwnerThread(current);return true;}}// 如果当前线程已经是锁的持有者(可重入)else if (current == getExclusiveOwnerThread()) {// 计算重入后的 stateint nextc = c + acquires;// 防止溢出if (nextc < 0)throw new Error("Maximum lock count exceeded");// 更新 statesetState(nextc);return true;}// 获取锁失败return false;}// 检查队列中是否有等待的节点(公平锁核心逻辑)public final boolean hasQueuedPredecessors() {// 等待队列的头节点Node h = head;// 等待队列的第二个节点Node s = tail;// 检查队列是否有等待的节点return h != null && s != null && h.next != s && s.thread != Thread.currentThread();}
}

条件变量实现原理
await流程

每个条件变量其实就对应着一个等待队列,其实现类是 ConditionObject

开始 Thread-0 持有锁,调用 await,进入 ConditionObject 的 addConditionWaiter 流程

public final void await() throws InterruptedException {// 1. 检查当前线程是否被中断if (Thread.interrupted())throw new InterruptedException();// 2. 将当前线程加入 Condition 的等待队列Node node = addConditionWaiter();// 3. 完全释放当前持有的锁(可重入锁需释放所有重入次数)int savedState = fullyRelease(node);// 4. 标记中断模式(0 表示未中断)int interruptMode = 0;// 5. 循环检查:当前节点是否已转移到 AQS 同步队列while (!isOnSyncQueue(node)) {// 5.1 挂起当前线程(等待被 signal 或中断唤醒)LockSupport.park(this);// 5.2 检查线程是否在等待过程中被中断if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)// 若被中断,跳出循环,处理中断逻辑break;}// 6. 线程被唤醒后,尝试重新获取锁(进入 AQS 同步队列的自旋逻辑)if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;// 7. 清理 Condition 等待队列中的取消节点if (node.nextWaiter != null) // 若有后续节点,清理取消的节点unlinkCancelledWaiters();// 8. 根据中断模式处理中断if (interruptMode != 0)reportInterruptAfterWait(interruptMode);
}

创建新的 Node 状态为 -2(Node.CONDITION),关联 Thread-0,加入等待队列尾部

private Node addConditionWaiter() {// 1. 获取 Condition 等待队列的尾节点(lastWaiter)Node t = lastWaiter;// 2. 检查尾节点是否有效(未被取消)// 如果尾节点存在,且其 waitStatus 不是 Node.CONDITION(说明已被取消)if (t != null && t.waitStatus != Node.CONDITION) {// 清理 Condition 队列中已取消的节点(unlinkCancelledWaiters 会遍历队列,移除 waitStatus != CONDITION 的节点)unlinkCancelledWaiters();// 重新获取尾节点(清理后可能变化)t = lastWaiter;}// 3. 创建新节点,封装当前线程,状态为 Node.CONDITIONNode node = new Node(Thread.currentThread(), Node.CONDITION);// 4. 将新节点加入 Condition 等待队列if (t == null) {// 如果队列为空(t == null),新节点作为第一个等待节点(firstWaiter)firstWaiter = node;} else {// 如果队列不为空,将新节点链到尾节点的 nextWaitert.nextWaiter = node;}// 更新尾节点为新创建的节点lastWaiter = node;// 5. 返回新创建的节点return node;
}

接下来进入 AQS 的 fullyRelease 流程,释放同步器上的锁

private Node addConditionWaiter() {// 1. 获取 Condition 等待队列的尾节点(lastWaiter)Node t = lastWaiter;// 2. 检查尾节点是否有效(未被取消)// 如果尾节点存在,且其 waitStatus 不是 Node.CONDITION(说明已被取消)if (t != null && t.waitStatus != Node.CONDITION) {// 清理 Condition 队列中已取消的节点(unlinkCancelledWaiters 会遍历队列,移除 waitStatus != CONDITION 的节点)unlinkCancelledWaiters();// 重新获取尾节点(清理后可能变化)t = lastWaiter;}// 3. 创建新节点,封装当前线程,状态为 Node.CONDITIONNode node = new Node(Thread.currentThread(), Node.CONDITION);// 4. 将新节点加入 Condition 等待队列if (t == null) {// 如果队列为空(t == null),新节点作为第一个等待节点(firstWaiter)firstWaiter = node;} else {// 如果队列不为空,将新节点链到尾节点的 nextWaitert.nextWaiter = node;}// 更新尾节点为新创建的节点lastWaiter = node;// 5. 返回新创建的节点return node;
}

unpark AQS 队列中的下一个节点,竞争锁,假设没有其他竞争线程,那么 Thread-1 竞争成功

park 阻塞 Thread-0

signal流程
public final void signal() {// 1. 检查当前线程是否持有锁(确保调用 signal 的线程是锁的持有者)if (!isHeldExclusively())// 如果当前线程未持有锁,抛出异常throw new IllegalMonitorStateException();// 2. 获取 Condition 等待队列的头节点(firstWaiter)Node first = firstWaiter;// 3. 如果头节点存在,唤醒该节点对应的线程if (first != null)// 调用 doSignal 处理唤醒逻辑doSignal(first);
}

假设 Thread-1 要来唤醒 Thread-0

进入 ConditionObject 的 doSignal 流程,取得等待队列中第一个 Node,即 Thread-0 所在 Node

private void doSignal(Node first) {// 循环处理 Condition 队列的节点do {// 1. 将头节点后移:firstWaiter 指向原头节点的下一个节点if ((firstWaiter = first.nextWaiter) == null)// 如果后移后队列为空,更新 lastWaiter 为 nulllastWaiter = null;// 2. 断开原头节点的 nextWaiter 链接(避免重复唤醒)first.nextWaiter = null;// 3. 尝试将节点从 Condition 队列转移到 AQS 同步队列//    如果 transferForSignal 失败(如节点已取消),继续尝试下一个节点} while (!transferForSignal(first) && // 获取新的头节点,继续循环(first = firstWaiter) != null);
}

执行 transferForSignal 流程,将该 Node 加入 AQS 队列尾部,将 Thread-0 的 waitStatus 改为 0,Thread-3 的 waitStatus 改为 -1

final boolean transferForSignal(Node node) {// 1. 尝试将节点的状态从 Node.CONDITION 改为 0(通过 CAS)//    - Node.CONDITION 是节点在 Condition 队列中的状态//    - 改为 0 表示节点即将转移到 AQS 同步队列if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; // 状态修改失败(节点可能已被取消)// 2. 将节点加入 AQS 同步队列(enq 会自旋确保节点入队)Node p = enq(node);int ws = p.waitStatus; // 获取前驱节点的状态// 3. 处理前驱节点的状态//    - 如果前驱节点状态是 CANCELLED(ws > 0),或 CAS 修改前驱状态为 SIGNAL 失败//    - 直接唤醒当前节点对应的线程,让其重新参与锁竞争if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread);return true; // 转移成功
}

Thread-1 释放锁,进入 unlock 流程,略

http://www.xdnf.cn/news/1278271.html

相关文章:

  • TC39x STM(System Timer)学习记录
  • 机器学习数学基础:46.Mann-Kendall 序贯检验(Sequential MK Test)
  • Spring Boot - 内置的9个过滤器用法
  • Day 9-2: Transformer翻译实例演示 - 翻译的基础设施
  • AI大模型 教师方向应用探索
  • Audio Flamingo
  • 第4章 程序段的反复执行4 多重循环练习(题及答案)
  • Python day40
  • C++ list类
  • 【深度学习新浪潮】遥感图像风格化迁移研究工作介绍
  • JS中typeof与instanceof的区别
  • 腾讯云EdgeOne KV存储在游戏资源发布中的技术实践与架构解析
  • 数学建模——回归分析
  • 【GPT入门】第44课 检查 LlamaFactory微调Llama3的效果
  • 集成电路学习:什么是Parameter Server参数服务器
  • 机器学习-增加样本、精确率与召回率
  • Java开源代码源码研究:我的成长之路与实战心得分享
  • 学习分库分表的前置知识:高可用系统架构理论与实践
  • 构建企业级Odoo 18 WMS——功能、架构与拓展蓝图
  • LeetCode每日一题,2025-8-10
  • 《C语言》结构体和联合体练习题--2
  • 前端学习日记 - 前端函数防抖详解
  • 无人机集群协同三维路径规划,采用梦境优化算法(DOA)实现,Matlab代码
  • python魔法属性__doc__介绍
  • 区块链让物联网真正链接万物
  • Mysql系列--5、表的基本查询(上)
  • 【论文阅读】Deep Adversarial Multi-view Clustering Network
  • C语言:指针(2)
  • 基于ECharts的智慧社区数据可视化
  • Knuth‘s TwoSum Algorithm 原理详解