最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Java 中 ReentrantLock 获取锁时的阻塞唤醒机制原理
时间:2026-07-13 09:10:46 编辑:袖梨 来源:一聚教程网
ReentrantLock 的阻塞与唤醒基于 AQS + LockSupport.park/unpark:获取失败时线程入 CLH 队列并 park() 暂停;释放锁时 unpark 队首线程使其重试竞争,非公平锁允许插队,全程规避 wait/notify 限制。
ReentrantLock 获取锁失败时的阻塞与唤醒,核心靠的是 AQS(AbstractQueuedSynchronizer) + LockSupport.park()/unpark() 这套组合,不是传统的 wait/notify。它更轻量、更灵活,也规避了 wait/notify 的诸多限制。
阻塞:线程怎么停下来等锁?
当线程调用 lock() 但锁已被占用,且不是自己重入时,AQS 会把该线程封装成一个 Node 节点,加入内部的 CLH 同步队列尾部,并执行 LockSupport.park() 让其暂停执行。
-
park()是 JVM 层提供的底层阻塞原语,不依赖 synchronized,也不要求在同步块中调用 - 被 park 的线程状态变为
WAITING,不消耗 CPU,也不会响应中断(除非用lockInterruptibly()) - 每个线程都有一个私有的“许可”(permit),
park()会消费这个 permit;如果没有 permit,线程就阻塞住
唤醒:谁来叫醒它?什么时候?
锁释放时(unlock()),AQS 会从同步队列头开始,尝试唤醒下一个等待节点——调用 LockSupport.unpark(thead) 给对应线程发放一个 permit,使其恢复运行。
- 唤醒动作由释放锁的线程完成,不是锁本身“主动通知”,而是 AQS 按队列顺序逐个 unpark
- 被 unpark 的线程重新进入锁竞争逻辑(
tryAcquire()),成功则获取锁继续执行;失败则可能再次 park(比如公平锁下还有前序节点) - 非公平锁允许新来的线程“插队”竞争,所以刚 unpark 的线程不一定立刻拿到锁
和 wait/notify 的关键区别在哪?
这套机制绕开了 Object 监视器模型的约束,解决了几个经典痛点:
立即学习“Java免费学习笔记(深入)”;
- 不用写在 synchronized 块里 ——
park/unpark可以在任意位置调用 - 不需要持有某个对象的 monitor —— 不再绑定特定对象实例
- 不会因虚假唤醒而意外返回 ——
park()只有收到 unpark 或被中断才会返回 - 支持精准唤醒 ——
unpark(Thread t)可指定唤醒哪个线程,不像notify()随机选一个
公平性如何影响唤醒行为?
公平锁和非公平锁在唤醒路径上差异明显:
- 公平锁:严格按 CLH 队列顺序唤醒,先到先得,保证 FIFO
- 非公平锁:释放锁后,先让新来的线程抢一次(CAS 尝试),抢不到才去唤醒队列头节点;这可能导致“插队”,提升吞吐但牺牲公平性
- 无论哪种,唤醒动作都只作用于队列头部节点,AQS 不会跳过中间节点
相关文章
- 天堂2盟约里巨蚁女王怎么打-天堂2盟约如何击败巨蚁女王 07-20
- 决胜之心 魂镜影介绍 07-20
- 迷你世界炎狱魔龙如何获得 炎狱魔龙技能图鉴 07-20
- 迷你世界厨房修建攻略 迷你世界厨房搭建方法 07-20
- 洛克王国世界s3赛季什么时候开始 07-20
- 绝区零希格莉德立绘合集 希格莉德值得抽吗 07-20