最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Java 中 synchronized 的内部工作原理:锁标记分析
时间:2026-07-10 10:28:57 编辑:袖梨 来源:一聚教程网
synchronized本质是基于对象监视器(Monitor)的互斥机制,由JVM通过对象头Mark Word动态控制锁状态;其锁升级过程为无锁→偏向锁→轻量级锁→重量级锁,单向不可逆,核心目标是减少用户态/内核态切换开销。
synchronized 的本质是基于对象监视器(Monitor)的互斥机制,其行为由 JVM 在运行时通过对象头中的 Mark Word 动态控制,而非简单“加一把固定锁”。理解它,关键不在语法,而在对象内存结构与锁状态的实时映射关系。
锁对象与 Monitor 的绑定关系
synchronized 从不“锁代码”,而是“锁对象”——所有同步操作最终都指向一个 Java 对象,该对象内部关联一个 Monitor 实例。Monitor 是 JVM 级别的同步组件,包含:
- _owner:当前持有锁的线程指针
- _EntryList:等待获取锁的阻塞线程队列
- _WaitSet:调用 wait() 后挂起的线程队列
当线程执行 monitorenter 指令(编译后插入同步块入口),JVM 就尝试将该线程设为 Monitor 的 _owner;执行 monitorexit 时则递减进入计数,归零后释放 Monitor 并唤醒 _EntryList 中的线程。
Mark Word:锁状态的动态存储区
每个 Java 对象的对象头中都有一个 Mark Word,它是锁升级的“状态寄存器”。在 64 位 JVM 中占 8 字节,其内容随锁状态变化而重解释:
立即学习“Java免费学习笔记(深入)”;
- 无锁状态:存放哈希码、GC 分代年龄、锁标志位(001)
- 偏向锁:记录偏向线程 ID、Epoch、分代年龄、锁标志位(101)
- 轻量级锁:存储指向当前线程栈中 Lock Record 的指针、锁标志位(00)
- 重量级锁:存储指向堆中 ObjectMonitor 对象的指针、锁标志位(10)
这种复用设计让同一片内存能承载不同语义,是锁优化的物理基础。
锁升级过程:从用户态到内核态的渐进切换
JDK 1.6 引入的锁升级机制,核心目标是避免过早陷入操作系统级阻塞(即重量级锁),减少用户态/内核态切换开销:
- 偏向锁:假设“单线程长期持有”,首次获取时仅用 CAS 设置线程 ID,后续进入几乎零成本
- 轻量级锁:检测到多线程竞争,升级为 CAS 自旋锁——线程在用户态循环尝试获取,不挂起
- 重量级锁:自旋失败或自旋耗时过长,JVM 调用操作系统 mutex,线程进入阻塞态,交由 OS 调度唤醒
升级是单向的(不可逆),但并非严格逐级——例如高竞争场景下,对象可能直接从无锁跳到重量级锁。
可重入性与内存语义保障
synchronized 天然可重入,依赖 Monitor 内部的 进入计数器(_recursions):每次加锁 +1,每次解锁 -1,仅当归零才真正释放 Monitor。
它同时提供三大并发原语保障:
- 原子性:Monitor 排他性确保临界区不被并发进入
- 可见性:锁释放前强制刷写工作内存到主内存;锁获取时强制从主内存读取最新值
- 有序性:在 monitorenter 和 monitorexit 前后插入内存屏障,禁止相关指令重排序
这些语义不是靠 Java 代码实现,而是 JVM 在字节码执行层面硬保证的底层契约。