轻量级锁升级为重量级锁由JVM自动触发,核心条件是自旋失败(超阈值、多线程竞争或持有线程执行过长),通过撤销轻量级状态、关联Monitor、更新Mark Word并交由OS阻塞线程来保障并发安全,且不可逆。

轻量级锁升级为重量级锁,不是靠手动触发,而是 JVM 在检测到竞争加剧时自动完成的。这个升级动作本身就是为了保障并发安全——当自旋已无法有效获取锁,继续空转只会浪费 CPU,此时必须让线程进入阻塞等待,由操作系统统一调度,避免忙等、保证公平性和状态一致性。
升级的核心条件:自旋失败
轻量级锁下,线程通过 CAS 尝试将对象头指向自己栈帧中的 Lock Record。若失败(说明有其他线程也在争抢),就进入自旋等待。JVM 不会无限自旋,而是按以下逻辑决定是否升级:
- 自旋次数超过阈值(默认 10 次,JDK 后期版本支持自适应自旋,根据历史成功率动态调整)
- 自旋期间有第三个及以上线程加入竞争(表明竞争从“交替”转向“密集”)
- 当前持有锁的线程执行时间过长,导致自旋线程长时间得不到响应
升级过程的关键保障点
升级不是简单改个标志位,而是一套原子、安全的状态迁移:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 撤销轻量级锁状态:JVM 先将对象头恢复为无锁状态(或直接跳过),再准备写入 Monitor 指针
- 分配并关联 Monitor 对象:每个 Java 对象在首次需要重量级锁时,JVM 会在堆中创建一个 C++ 实现的 Monitor 结构,包含 Owner、EntryList、WaitSet 等字段
- 更新 Mark Word:用 CAS 将对象头的 Mark Word 替换为指向该 Monitor 的指针,锁标志位设为 10
- 线程挂起交由 OS 管理:未获取锁的线程被放入 Monitor 的 EntryList,并调用操作系统 pthread_mutex_lock 等原语进入阻塞态,不再占用 CPU
为什么这样就能保证并发安全?
因为重量级锁把同步责任移交给了操作系统内核:
立即学习“Java免费学习笔记(深入)”;
- 阻塞与唤醒由 OS 调度器精确控制,避免了用户态自旋带来的竞态和资源浪费
- Monitor 内部通过互斥量(Mutex)+ 条件变量(Condition Variable)实现排队、通知、重入校验等完整语义
- 所有对共享变量的读写,都自然落在 synchronized 块的内存屏障约束下,确保可见性与有序性
注意:升级不可逆,且影响范围仅限该对象
一旦某个对象的锁升级为重量级,它后续所有同步操作都会走 Monitor 路径,不会再降级。但这个升级是对象粒度的——不影响其他对象,也不影响同一类的其他实例。所以合理设计锁粒度(比如避免用 this 或 class 锁住大段逻辑),仍是减少重量级锁滥用的关键。

















