轻量级锁本身不自旋,竞争时线程先自旋尝试CAS获取锁,失败后触发锁膨胀:JVM创建ObjectMonitor并将Mark Word指向它,锁升级为重量级锁。

Java 中轻量级锁不会“自旋升级”为重量级锁,这是一个常见误解。轻量级锁本身不包含自旋机制;真正涉及自旋的是 偏向锁撤销后进入的轻量级锁竞争阶段,以及后续 锁膨胀(inflate)为重量级锁 的过程。是否升级、何时升级,取决于 JVM 的竞争检测策略,而非固定次数的自旋。
轻量级锁的竞争与膨胀触发条件
当多个线程交替或同时尝试获取同一把轻量级锁时,JVM 会通过 CAS 尝试将对象头中的 Mark Word 替换为指向当前线程栈中 Lock Record 的指针。若失败(说明有其他线程正持有或正竞争该锁),当前线程会:
- 先进行一定次数的 自旋(spin) —— 即在用户态循环重试 CAS,避免立即挂起线程;
- 自旋成功则直接获取锁,不升级;
- 自旋失败(达到阈值或被调度器打断),则触发 锁膨胀:JVM 在堆中创建一个 ObjectMonitor 对象,将 Mark Word 更新为指向该 monitor 的指针,锁正式变为重量级锁;
- 此时再争抢锁的线程,将被挂起并加入 monitor 的 _WaitSet 或 _EntryList,进入操作系统互斥量等待。
自旋次数不是硬编码,由 JVM 动态调整
JVM 并不使用固定自旋次数(如 “10 次”)。是否自旋、自旋多久,取决于:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- -XX:+UseSpinning(JDK 6 默认开启,JDK 7+ 已默认启用且不可关闭);
- -XX:PreBlockSpin(仅 JDK 6 有效,设置初始自旋次数,默认 10);
- 更关键的是 自适应自旋(Adaptive Spinning):JVM 会根据前一次在该锁上自旋是否成功,动态调整本次自旋时长(如成功则延长,失败则缩短甚至跳过);
- 实际自旋还受 CPU 核心数、系统负载、是否超时等因素影响,由 HotSpot 的 ObjectSynchronizer::fast_enter 和 ObjectSynchronizer::slow_enter 流程控制。
重量级锁不是“升级结果”,而是竞争下的自然选择
所谓“升级”只是描述性说法。本质上:
立即学习“Java免费学习笔记(深入)”;
- 偏向锁 → 被撤销(因竞争)→ 进入无锁或轻量级锁状态;
- 轻量级锁 → 竞争激烈(CAS 失败 + 自旋无效)→ 创建 ObjectMonitor → Mark Word 指向它 → 锁表现为重量级语义;
- 这个过程不可逆:一旦膨胀为重量级锁,该对象后续所有同步操作都走 monitor 逻辑,即使竞争消失也不会“降级”回轻量级锁(JDK 10 引入了可选的锁降级实验特性,但默认关闭且不用于轻量级锁回退)。

















