synchronized锁升级是JVM根据竞争程度渐进式启用的防御机制:无锁(Mark Word存哈希码,标志位01)→偏向锁(CAS记录线程ID,标志位仍01)→轻量级锁(自旋+Lock Record,标志位00)→重量级锁(OS Monitor,标志位10),单向不可降级。

理解 synchronized 锁升级,关键不是背四个状态名称,而是看清 JVM 如何根据真实竞争情况,用最小代价守住线程安全。它本质是一套“渐进式防御机制”:没敌人就闲着,来一个熟人就开门放行,来两个陌生人就简单盘查,真打起来才叫保安(操作系统)介入。
无锁是起点,不是“没锁”
对象刚创建时,Mark Word 里存的是哈希码、GC年龄等信息,锁标志位是 01。这时没有线程持有锁,也不代表“不需要锁”,只是还没触发同步行为。只要没线程执行到 synchronized 块,它就一直保持这个干净状态——零开销,零干预。
偏向锁解决“自己人反复进门”的问题
当第一个线程进入 synchronized 块时,JVM 会尝试把它“记在本子上”:
- 通过一次 CAS 把当前线程 ID 写入 Mark Word,并把偏向标志位置为 1(此时锁标志位仍是 01)
- 之后该线程再次进入,只比对线程 ID 是否匹配,不加锁、不 CAS、不挂起——快得像没锁一样
- 一旦其他线程来抢,JVM 就必须在全局安全点暂停所有线程,撤销偏向(清空线程 ID),然后升级为轻量级锁
轻量级锁靠“自旋”避免系统调用
多个线程交替抢锁但不激烈时,JVM 不急着叫操作系统,而是让线程在用户态“原地等待”:
立即学习“Java免费学习笔记(深入)”;
- 每个线程在自己栈帧里建一个 Lock Record,把原 Mark Word 备份进去
- 用 CAS 把 Mark Word 替换为指向这个记录的指针(锁标志位变成 00)
- CAS 失败说明有竞争,线程就自旋(空循环)若干次(默认 10 次),再失败就准备升级
自旋不耗 CPU?错——它占着 CPU 白跑,但比进内核态切换上下文便宜得多。适合锁持有时间极短的场景。
重量级锁是最后防线,靠操作系统兜底
当自旋失败、竞争线程变多或锁被长时间持有,JVM 就把控制权交给操作系统:
- Mark Word 被替换成指向 Monitor 对象的指针(锁标志位变为 10)
- 抢不到锁的线程被挂起,进入阻塞队列,由 OS 调度唤醒
- 这一步涉及用户态→内核态切换,开销大,但能真正释放 CPU 给其他任务
锁升级是单向的:无锁 → 偏向锁 → 轻量级锁 → 重量级锁。升上去就不会降下来,因为降级要处理更多并发边界,得不偿失。


















