synchronized 的升级过程(精简 & 好笑版)

一句话总结

synchronized 的锁,会随着竞争程度一路“升职”,但只升不降。


一、synchronized 是干嘛的?

很简单:
👉 保证同一时刻,只有一个线程能干活
👉 顺便还送你一张 happens-before 的内存可见性门票

本质上,它就是在用 对象自带的监视器锁(Monitor)


二、锁升级路线图(主线剧情)

1
无锁 → 偏向锁(已退休) → 轻量级锁 → 重量级锁

记住一句话就够了:

竞争越激烈,锁越“重”。


三、四种锁,用一句话讲清楚

1️⃣ 无锁:世界很和平

  • 没人抢,直接用
  • 性能最好
  • 对象头里就是普通信息

🧘:“今天没人吵架。”


2️⃣ 偏向锁:对象只爱一个线程(已退役)

  • 第一次用锁的线程,被对象“记住”
  • 后面再来,连 CAS 都懒得做
  • Java 15+ 默认禁用,已弃用

💔:“曾经专一,现在分手。”


3️⃣ 轻量级锁:礼貌地抢

  • 多线程来了,但不算多
  • CAS + 自旋
  • 运行在 用户态(Ring 3)
  • 不阻塞,先忙等一会儿

🤺:“我先转几圈看看你放不放手。”


4️⃣ 重量级锁:直接叫警察

  • 竞争太激烈了
  • 直接上 操作系统互斥锁
  • 线程 阻塞
  • 进入 内核态(Ring 0)

🚨:“别吵了,全体排队!”


四、轻量级 vs 重量级(记住这张表)

对比项 轻量级锁 重量级锁
运行位置 用户态(Ring 3) 内核态(Ring 0)
手段 CAS + 自旋 OS Mutex
线程状态 RUNNABLE BLOCKED
上下文切换
适合场景 低竞争 高竞争

一句话版:

抢得不狠,用轻量级;打成一团,上重量级。


五、锁升级阈值能调吗?

不能精确调。

JVM 内心戏很多,会自己判断:

  • 自旋次数
  • 历史竞争情况
  • CPU 忙不忙

你最多只能:

1
-XX:+DisableFatLockSpin

意思是:

“重量级锁别自旋了,直接睡。”


六、Ring 0 / Ring 3 到底在说啥?

  • Ring 3(用户态)
    👉 轻量级锁、自旋、CAS
    👉 快,但得自己忙等

  • Ring 0(内核态)
    👉 重量级锁、线程阻塞
    👉 慢,但省 CPU

🧠 JVM 的哲学:

能不进内核,就不进内核。


七、为什么要搞这么复杂?

因为现实很残酷:

  • 没竞争 👉 不该付出代价
  • 低竞争 👉 不该进内核
  • 高竞争 👉 CPU 不能白烧

所以 JVM 选择:

让锁自己“看情况做人”。


八、终极总结(面试可用)

  • synchronized 不是一上来就重量级
  • 锁升级 只升不降
  • 轻量级锁在 用户态
  • 重量级锁进 内核态
  • 偏向锁 已成历史

🎯 一句话收尾:

synchronized 的本质,就是 JVM 在性能和公平之间反复横跳。