ReentrantLock释放锁时只唤醒同步队列中首个有效等待节点:先检查next节点是否为null或已取消(waitStatus>0),若是则从尾部向前遍历找未取消节点,再unpark;被唤醒线程需重新执行acquireQueued流程,调用tryAcquire竞争锁,成功才成为新头节点,唤醒不保证立即获锁。

Java 中独占锁(如 ReentrantLock 底层使用的 AQS)在释放锁时,会尝试唤醒同步队列中排在最前面的等待节点(即后继节点),但这个“唤醒”不是简单地调用 unpark 就完事——它有一套判断逻辑,核心是:**只唤醒真正需要被唤醒的、处于阻塞等待状态的后继节点**。
唤醒前先检查后继节点是否有效
AQS 的 release 流程中,调用 unparkSuccessor 方法负责唤醒后继节点。该方法会:
- 从当前节点的
next字段读取后继节点; - 如果后继节点为
null或已取消(waitStatus > 0),就从队列尾部向前遍历,找第一个未取消的节点; - 只对这个“有效后继节点”执行
LockSupport.unpark(node.thread)。
为什么不能直接 unpark next?
因为并发环境下,后继节点可能在入队后又因超时、中断或条件不满足而主动取消等待,此时它的 waitStatus 被设为 CANCELLED(值为 1)。若盲目 unpark 已取消的线程,不仅无意义,还可能干扰其正常清理逻辑。AQS 选择跳过这些节点,确保唤醒的是仍需竞争锁的活跃等待者。
被唤醒的节点如何继续执行?
被 unpark 的线程从 LockSupport.park 返回后,并不会立即获得锁,而是重新进入 AQS 的 acquireQueued 主循环:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 检查自己是否为队列头节点的后继(即是否轮到自己尝试获取锁);
- 调用
tryAcquire尝试获取同步状态; - 若成功,将自己设为新的头节点,并退出等待;
- 若失败,且仍需等待,则可能再次 park(取决于是否可被中断或有超时)。
注意:唤醒不保证立即抢到锁
唤醒只是让线程“有机会参与竞争”,不代表它能立刻获得锁。比如:
- 刚被唤醒的线程还在恢复上下文、重新检查状态,此时其他线程可能抢先调用
acquire并成功获取锁; - 多个线程被唤醒后并发执行
tryAcquire,最终只有一个能成功,其余仍需等待或重试。
不复杂但容易忽略:唤醒动作本身是轻量的,关键在于 AQS 通过状态管理和队列维护,让唤醒精准、安全、可重入。

















