关键在于避免为“几乎不竞争”的场景付出昂贵代价:偏向锁专为单线程反复访问设计,通过线程ID比对免CAS;轻量级锁以自旋+有限CAS应对短暂低频竞争;二者递进升级且不可逆。

理解 synchronized 的偏向锁和轻量级锁,关键不是背状态切换流程,而是抓住 JVM 设计它们的出发点:**避免为“几乎不竞争”的场景付出昂贵代价**。
偏向锁:专为“单线程反复用”而生
它假设“这个锁大概率只会被同一个线程访问”。对象刚创建时无锁;当第一个线程执行 synchronized 块时,JVM 就把对象头里的“偏向锁位”设为 1,并存入该线程 ID。之后这个线程再进同一块同步代码,只需比对对象头中的线程 ID 是否匹配,匹配就直接执行——全程不走 CAS,也不涉及任何锁操作开销。
适用情况包括:
- 单线程环境下的初始化逻辑(如 Spring Bean 构造、静态工具类首次调用)
- 线程池中复用的 Runnable/Callable,其内部同步块由同一线程反复执行
- Web 应用中某些仅在启动阶段由主线程完成的配置加载
注意:一旦有第二个线程尝试获取该锁,偏向锁就会被撤销(revoke),升级为轻量级锁。撤销本身有开销,所以如果业务天然存在多线程争抢,反而应禁用偏向锁(-XX:-UseBiasedLocking)。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
轻量级锁:应对“短暂、低频竞争”的折中方案
当偏向锁被打破,或对象一开始就不支持偏向(如已禁用),JVM 就启用轻量级锁。它的核心是“自旋 + CAS”:线程在自己的栈帧里建一个 Lock Record,然后用 CAS 尝试把对象头的 Mark Word 替换为指向这个记录的指针。成功即获得锁;失败则说明有竞争,进入自旋等待。
自旋不是无限等,而是有限次数(默认 10 次),且只在锁持有时间极短、线程能快速释放的前提下才高效。它避免了立即陷入内核态阻塞,但会持续占用 CPU。
典型触发场景有:
- 两个线程交替执行同一段同步代码(如简单计数器的增减)
- 临界区非常小(几条赋值或加法指令),且线程切换成本远高于自旋成本
- CPU 核心充足,允许短时间空转而不显著影响整体吞吐
二者关系与升级逻辑
偏向锁和轻量级锁不是并列选项,而是递进关系:
- 无锁 → 偏向锁(首个线程进入)
- 偏向锁 → 轻量级锁(出现竞争,撤销偏向)
- 轻量级锁 → 重量级锁(自旋失败超阈值,或等待线程过多)
这个升级链条不可逆。JVM 不会因为竞争消失就把重量级锁降回轻量级,因为降级需要额外同步协调,得不偿失。所以优化重点在于:让锁尽量停留在前两级,而不是频繁升级到重量级。

















