源码:java.util.concurrent.locks.LockSupport 源码解析
1. TODO
2. 脑图
Xmind
Edraw
Hexo 地址
👉 http://blog.wangjia.ink/2025/11/13/源码:java.util.concurrent.locks.LockSupport源码解析/
3. 基础部分
3.1. LockSupport 概述
想象这样几个问题:
Object#wait、Object#notify和synchronized是绑定的,它们必须出现在synchronized代码块中。也就是说:为了实现一次 “等待” 或 “通知”,线程必须先去竞争到Monitor锁。而在高并发场景下,这种对Monitor锁的竞争是重量级的Object#notify()是唤醒Monitor的WaitSet中的 “任意” 一个Thread实例。而Object#notifyAll()是唤醒Monitor的WaitSet中的所有Thread实例,导致 “惊群效应”。它们都没有办法精确唤醒我们指定要唤醒的线程- 除此之外,还有一个经典的竞态条件:如果本地线程
B调用Object#notify先于本地线程A调用Object#wait,那么这个Object#notify就永久消失了,本地线程A将 ”无限期“ 地等待一个永远不会再来的Object#notify。而我们往常解决的方法是:在使用Object#wait、Object#notify前,要先用while(condition)循环来检查状态,非常的繁琐
为了解决这一问题,Doug Lea 就封装了 LockSupport,我们在 AQS 中实现的阻塞、唤醒都是基于 LockSupport
在 LockSupport 体系下,我们可以把每个本地线程想象成一个需要持有 “许可证” 才能继续运行的人。这个许可证不是计数器,不会累加,只有两种状态:1 和 0
当我们调用 LockSupport.unpark 唤醒某本地线程时,无论该本地线程是阻塞还是运行,都会为它发放一个 “许可证”
而当我们调用 LockSupport.park 时,本地线程会先检查自己是否持有许可证:
- 如果持有许可证
- 消耗许可证(许可证从
1 ➔ 0),继续向下执行
- 消耗许可证(许可证从
- 如果未持有许可证
- 让本地线程进入阻塞状态,
Thread实例进入BWTW状态,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时
- 让本地线程进入阻塞状态,
[!NOTE] 注意事项
LockSupport.unpark可以先于LockSupport.park执行,而不会 ”条件消失“,这是Doug Lea封装它的核心原因
4. 源码部分
1 | |
源码:java.util.concurrent.locks.LockSupport 源码解析
https://wangjia5289.github.io/2025/11/13/源码:java.util.concurrent.locks.LockSupport源码解析/