synchronized锁升级是jvm按竞争程度从轻到重的优化策略:偏向锁面向单线程场景,仅首次cas记录线程id;轻量级锁面向低竞争,通过cas+自旋避免内核态切换。

理解 synchronized 的锁升级,关键不是背状态名,而是看 JVM 怎么“省事”——它会按竞争程度,从最轻量的方式开始尝试,只在不得已时才加重开销。偏向锁和轻量级锁正是这种“能不动真格就不动真格”策略的两个典型阶段。
偏向锁:专为“单线程反复用一把锁”设计
它不解决多线程竞争,反而假设“大概率只有你一个线程会来”。一旦某个线程第一次进入 synchronized 块,JVM 就悄悄在对象头(Mark Word)里记下它的 ID,并打上“偏向”标记。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 之后这个线程再进来,只需比对一下 ID 是否匹配,匹配就直接执行,连 CAS 都不触发
- 其他线程来抢?不是立刻升级,而是先尝试撤销偏向(revoke),把对象头恢复成“可竞争”状态,然后走下一步
- 偏向锁默认延迟 4 秒开启,可用 -XX:-UseBiasedLocking 关闭;它不主动释放,只在有竞争时被撤销
轻量级锁:多个线程“轮流快进快出”的折中方案
当偏向锁被撤销,或一开始就不适合偏向(比如构造对象后立即被多线程访问),JVM 就启用轻量级锁。它不再记录线程 ID,而是在当前线程栈帧里建一个“锁记录”(Lock Record),再用 CAS 把对象头替换成指向这个记录的指针。
- CAS 成功 → 拿到锁,进入同步块
- CAS 失败 → 说明正被别的线程持有,当前线程开始自旋(空转等待一小会儿)
- 自旋一定次数(JDK 默认约 10 次)或超过阈值时间(如 1ms),仍没等到锁,就升级为重量级锁
两者本质区别在哪
偏向锁是“无竞争优化”,靠的是“信任第一个线程”;轻量级锁是“低竞争优化”,靠的是“自旋+CAS 不进内核态”。前者零同步开销(仅首次有 CAS),后者有少量原子操作和自旋消耗,但远低于挂起线程、切换内核态的代价。它们都不是独立存在的锁类型,而是同一把锁在不同竞争强度下的表现形态。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










