ReentrantLock释放锁时仅唤醒AQS同步队列中头节点的第一个有效后继节点,不涉及条件队列;条件队列唤醒需显式调用signal()或signalAll(),且signal()仅将节点移至同步队列尾部,真正获取锁仍需等待unlock()触发的唤醒流程。

ReentrantLock 释放锁时,会唤醒 AQS 同步队列(即等待获取锁的队列)中头节点的后继节点,而不是直接通知条件队列(ConditionQueue)——条件队列的唤醒需显式调用 signal() 或 signalAll()。
释放锁触发的是同步队列的唤醒
ReentrantLock 的 unlock() 最终调用 AQS 的 release(int arg) 方法:
- 先尝试
tryRelease(arg):在 ReentrantLock 中,该方法会减少重入计数;若计数归零,则真正释放锁,并把 AQS 的exclusiveOwnerThread设为null;返回true表示完全释放成功。 - 若释放成功,接着调用
unparkSuccessor(Node node)唤醒同步队列中头节点(当前已释放锁的节点)的**第一个有效后继节点**(跳过已取消的节点)。 - 被唤醒的线程会在下一次自旋中尝试
acquireQueued()获取锁,重新竞争。
条件队列(await/signal)是独立机制
ReentrantLock 关联的 ConditionObject 维护自己的等待队列(条件队列),与 AQS 同步队列分离:
-
await()会将当前线程加入条件队列,并**完全释放锁**(调用fullyRelease()),然后阻塞;此时线程不在 AQS 同步队列中。 -
signal()不释放锁,只是把条件队列首节点移到 AQS 同步队列尾部,并唤醒它(不立即抢锁,而是等锁释放后参与竞争)。 - 只有当持有锁的线程随后调用
unlock(),才会触发 AQS 的正常唤醒流程,让刚转移过来的线程有机会获取锁。
关键细节:唤醒不是“广播”,而是精准 unpark
AQS 不使用 notify/notifyAll 这类 JVM 级通知,而是基于线程对象直接调用 LockSupport.unpark(Thread):
立即学习“Java免费学习笔记(深入)”;
- 每个 Node 持有其对应线程的引用(
thread字段),唤醒时直接操作该线程。 - 被
unpark()的线程不会立即执行,而是从park()阻塞点恢复,继续自旋尝试获取锁。 - 没有锁竞争时,唤醒后通常能立刻成功获取;若有竞争,则再次入队等待。
注意:释放锁本身不感知条件队列
单纯调用 unlock() 对任何 Condition 都无影响。如果希望释放锁的同时唤醒等待条件的线程,必须显式配对:
-
错误写法:
lock.unlock();—— 条件队列里的线程继续沉睡。 -
正确写法:
condition.signal(); lock.unlock();或lock.unlock();之后由其他线程调用 signal。


















