JUC学习笔记-----ReentrantLock

目录

ReentrantLock原理

[1. 非公平锁实现原理](#1. 非公平锁实现原理)

加锁成功流程

加锁失败流程

解锁竞争成功流程

解锁竞争失败流程

可重入原理

可打断模式

不可打断模式

可打断模式

公平锁实现原理

条件变量实现原理

await流程

signal流程


ReentrantLock原理

1. 非公平锁实现原理

加锁成功流程

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

java 复制代码
public ReentrantLock() {
 sync = new NonfairSync();
}

NonfairSync 继承自 AQS

没有竞争时

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

java 复制代码
// 非公平锁的实现类,继承自 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,结果失败
  1. 进入 tryAcquire 逻辑,这时 state 已经是1,结果仍然失败的
java 复制代码
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();
}
  1. 接下来进入 addWaiter 逻辑,构造 Node 队列

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

Node 的创建是懒惰的

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

当前线程进入 acquireQueued 逻辑

java 复制代码
// 方法作用:让节点在 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 标记获取锁成功,后续不再执行 cancelAcquire
                failed = false;
                // 2.4 返回中断状态(false 表示未被中断)
                return interrupted;
            }
            // 3. 获取锁失败:判断是否需要挂起当前线程
            if (shouldParkAfterFailedAcquire(p, node) &&
                // 3.1 挂起线程,并检查是否被中断
                parkAndCheckInterrupt()) 
                // 3.2 如果被中断,标记 interrupted 为 true
                interrupted = true;
        }
    } finally {
        // 4. 如果获取锁失败(failed 仍为 true),取消当前节点在队列中的等待
        if (failed)
            cancelAcquire(node);
    }
}
  1. acquireQueued 会在一个死循环中不断尝试获得锁,失败后进入 park 阻塞

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

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

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

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

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

java 复制代码
// 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 流程

java 复制代码
// 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 流程

java 复制代码
// 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),返回 false
    return false;
}
java 复制代码
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 流程

java 复制代码
// 方法作用:让节点在 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 标记获取锁成功,后续不再执行 cancelAcquire
                failed = false;
                // 2.4 返回中断状态(false 表示未被中断)
                return interrupted;
            }
            // 3. 获取锁失败:判断是否需要挂起当前线程
            if (shouldParkAfterFailedAcquire(p, node) &&
                // 3.1 挂起线程,并检查是否被中断
                parkAndCheckInterrupt()) 
                // 3.2 如果被中断,标记 interrupted 为 true
                interrupted = 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

java 复制代码
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. 抢占失败且不可重入,返回 false
        return 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 重新触发中断,保证业务逻辑能感知到中断事件,同时不影响锁竞争流程。

java 复制代码
// 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);
                    // 断开前驱节点引用,协助 GC
                    p.next = null;
                    // 标记获取锁成功,后续 finally 不执行 cancelAcquire
                    failed = false;
                    // 返回中断状态(需获取锁后才反馈中断)
                    return interrupted;
                }
                // 若获取锁失败,判断是否需要挂起线程,并处理中断
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt()) {
                    // 若因中断唤醒,标记 interrupted 为 true
                    interrupted = 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();
    }
}
可打断模式
java 复制代码
static final class NonfairSync extends Sync {

    // 可中断的锁获取方法
    // arg:获取锁的参数(通常为 1)
    public final void acquireInterruptibly(int arg) throws InterruptedException {
        // 检查当前线程是否已中断
        if (Thread.interrupted())
            // 若已中断,抛出 InterruptedException
            throw 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()) {
                    // 若被中断,抛出 InterruptedException
                    throw new InterruptedException();
                }
            }
        } finally {
            // 如果获取锁失败(failed 为 true),取消当前节点的等待
            if (failed)
                cancelAcquire(node);
        }
    }
}
公平锁实现原理
java 复制代码
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()) {
            // 计算重入后的 state
            int nextc = c + acquires;
            // 防止溢出
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            // 更新 state
            setState(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 流程

java 复制代码
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,加入等待队列尾部

java 复制代码
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.CONDITION
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    
    // 4. 将新节点加入 Condition 等待队列
    if (t == null) {
        // 如果队列为空(t == null),新节点作为第一个等待节点(firstWaiter)
        firstWaiter = node;
    } else {
        // 如果队列不为空,将新节点链到尾节点的 nextWaiter
        t.nextWaiter = node;
    }
    // 更新尾节点为新创建的节点
    lastWaiter = node;
    
    // 5. 返回新创建的节点
    return node;
}

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

java 复制代码
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.CONDITION
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    
    // 4. 将新节点加入 Condition 等待队列
    if (t == null) {
        // 如果队列为空(t == null),新节点作为第一个等待节点(firstWaiter)
        firstWaiter = node;
    } else {
        // 如果队列不为空,将新节点链到尾节点的 nextWaiter
        t.nextWaiter = node;
    }
    // 更新尾节点为新创建的节点
    lastWaiter = node;
    
    // 5. 返回新创建的节点
    return node;
}

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

park 阻塞 Thread-0

signal流程
java 复制代码
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

java 复制代码
private void doSignal(Node first) {
    // 循环处理 Condition 队列的节点
    do {
        // 1. 将头节点后移:firstWaiter 指向原头节点的下一个节点
        if ((firstWaiter = first.nextWaiter) == null)
            // 如果后移后队列为空,更新 lastWaiter 为 null
            lastWaiter = 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

java 复制代码
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 流程,略