跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java synchronized 底层原理:字节码、对象头与锁升级

synchronized 基于 monitorenter 和 monitorexit 指令实现同步。JVM 通过对象头 Mark Word 记录锁状态,利用 Monitor 管理线程阻塞与等待。锁升级路径为无锁至偏向锁、轻量级锁再到重量级锁,旨在减少性能开销。硬件层面依赖内存屏障保证可见性与有序性,CAS 保障原子性。理解这些机制有助于优化高并发场景下的代码性能。

SqlMaster发布于 2026/2/17更新于 2026/9/1858 浏览
Java synchronized 底层原理:字节码、对象头与锁升级

synchronized 是 Java 中最基础的同步机制,其底层实现涉及字节码指令、JVM 内存模型以及操作系统层面的互斥锁。理解它的工作原理,对于排查并发问题和优化性能至关重要。

1. 字节码层面:monitorenter 和 monitorexit

当编译器处理 synchronized 关键字时,会根据上下文生成特定的字节码指令。无论是修饰代码块还是方法,核心都在于锁的获取与释放。

同步代码块

对于 synchronized(object) { ... } 结构,编译器会在同步块前后分别插入 monitorenter 和 monitorexit 指令。值得注意的是,为了应对异常,编译器通常会生成两个 monitorexit 指令:一个用于正常退出,另一个包裹在异常处理逻辑中(类似 finally),确保即使发生异常锁也能被正确释放。

public void method() {
    synchronized (obj) {
        System.out.println("hello");
    }
}

反编译后的字节码大致如下:

public void method();
Code:
   0: aload_0
   1: getfield      #2                  // Field obj:Lcom/example/Obj;
   4: dup
   5: astore_1
   6: monitorenter                          // 尝试获取锁
   7: getstatic     #3                    // Field java/lang/System.out:Ljava/io/PrintStream;
  10: ldc           #4                    // String hello
  12: invokevirtual #5                    // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  15: aload_1
  16: monitorexit                           // 正常退出,释放锁
  17: goto          25
  20: astore_2
  21: aload_1
  22: monitorexit                           // 异常退出,释放锁
  23: aload_2
  24: athrow
  25: return

同步方法

对于 synchronized 修饰的方法,常量池中会设置 ACC_SYNCHRONIZED 标志。调用该方法的指令(如 invokevirtual)在执行前会检查此标志。若存在,线程需先尝试获取锁(实例方法为 this,静态方法为 Class 对象),执行完方法体后自动释放锁。

2. JVM 底层实现:对象头与 Monitor

monitorenter 和 monitorexit 的具体行为由 JVM 管理,核心依赖于 Java 对象头 和 Monitor。

2.1 Java 对象头(Mark Word)

在 HotSpot 虚拟机中,对象内存布局包含对象头、实例数据和对齐填充。其中对象头是关键,它包含两部分信息:

  1. Mark Word:存储对象运行时的元数据,如哈希码、GC 分代年龄、锁状态标志、偏向线程 ID 等。它是锁状态变化的'主战场'。
  2. Klass Pointer:指向类元数据的指针,确定对象类型。

Mark Word 是一个动态数据结构,根据对象状态复用存储空间。在 32 位 JVM 下,最后 2 位(lock)标识了对象的锁状态,锁的升级过程就体现在这 2 位的变化上。

文章配图

2.2 Monitor(管程/监视器锁)

每个对象都关联了一个内置的 Monitor。monitorenter 的本质就是尝试获取这个 Monitor。

Monitor 内部维护了三个关键属性:

  • Owner:当前持有锁的线程,同一时刻只能有一个。
  • EntryList:处于 Blocked 状态的等待队列。当 Owner 释放锁时,JVM 会从 EntryList 中挑选线程竞争。
  • WaitSet:处于 Waiting 状态的线程队列,通常由调用 Object.wait() 产生。

工作流程简述:

  1. 线程执行 monitorenter 时,检查 Monitor 的 Owner。
  2. 若 Owner 为空,当前线程成为 Owner,锁计数器 +1。
  3. 若 Owner 是当前线程(可重入),计数器 +1。
  4. 若 Owner 是其他线程,当前线程进入 EntryList 阻塞。
  5. 执行 monitorexit 时,计数器 -1。归零时释放 Monitor,唤醒 EntryList 中的线程。
3. 锁的升级与优化

Java 6 之前,synchronized 直接依赖操作系统的 Mutex Lock,涉及用户态到内核态切换,开销大。Java 6 引入了锁升级机制,路径为单向不可逆:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁。

3.1 偏向锁
  • 场景:没有竞争,总是由同一线程获取锁。
  • 原理:首次加锁时将线程 ID 写入 Mark Word。后续该线程再次进入无需 CAS 操作,仅测试 Mark Word 即可。
  • 撤销:一旦有其它线程尝试竞争,偏向模式结束,升级为轻量级锁。

注:Java 15+ 已废弃偏向锁,默认禁用,但理解其原理对掌握锁机制仍有意义。

3.2 轻量级锁
  • 场景:竞争不激烈,线程交替执行。
  • 加锁:在当前线程栈帧创建 锁记录(Lock Record),将对象头复制到锁记录中。使用 CAS 尝试将对象头替换为指向锁记录的指针。成功则获得锁,失败则说明有竞争。
  • 解锁:使用 CAS 将锁记录中的 Mark Word 恢复回对象头。若失败,说明锁已膨胀,需唤醒阻塞线程。

文章配图

3.3 重量级锁
  • 触发:轻量级锁竞争失败且自旋一定次数后,或偏向锁撤销后。
  • 特点:Mark Word 指向重量级锁(Monitor)。等待线程进入 EntryList 阻塞,依赖操作系统互斥锁,成本最高。

文章配图

4. 硬件层面:内存屏障与 CAS

synchronized 保证了原子性、可见性和有序性。

  • 可见性与有序性:通过插入 内存屏障 实现。同步块开始处加 Load Barrier,结束时加 Store Barrier,强制刷新工作内存到主内存,禁止指令重排序。
  • 原子性:简单的 monitorenter/monitorexit 由 Monitor 保证;锁状态变更(如轻量级锁获取)则依赖 CPU 提供的 CAS 原子指令(如 cmpxchg)。

理解这些底层细节,能帮助我们在高并发场景下更合理地设计同步策略,避免不必要的性能损耗。

目录

  1. 1. 字节码层面:monitorenter 和 monitorexit
  2. 2. JVM 底层实现:对象头与 Monitor
  3. 2.1 Java 对象头(Mark Word)
  4. 2.2 Monitor(管程/监视器锁)
  5. 3. 锁的升级与优化
  6. 3.1 偏向锁
  7. 3.2 轻量级锁
  8. 3.3 重量级锁
  9. 4. 硬件层面:内存屏障与 CAS

更多推荐文章

查看全部
  • PyTorch 实战:基于文本引导的图像生成与 Stable Diffusion 实践
  • 网络安全人才缺口巨大为何招聘却少?深度解析行业现状
  • OpenClaw 本地 AI 助手部署与飞书对接指南
  • 构建通用 AI 智能体应用的核心技术指南
  • Qt 与 Linux Socket 跨平台通信实战指南
  • MySQL 核心知识点详解:索引、设计、事务与视图
  • n8n 开源自动化工作流工具部署与使用指南
  • 30+ 大语言模型(LLM)面试问题及答案详解
  • AI 时代重读《人人都是产品经理》:经典产品内核的当代价值
  • FPGA 读写 DDR4(一)MIG IP 核控制信号
  • FastAPI:Python 高性能 Web 框架核心特性与性能分析
  • 渗透测试流程详细讲解
  • 基于 Go 语言的命令行 AI 对话客户端开发实战
  • 让 AI 文案更像人写的 15 条提示词
  • Docker Desktop 启动报错虚拟化支持未检测到的解决方法
  • 使用 Anaconda 安装 NumPy、Pandas、Scikit-learn 及 Seaborn
  • 人工智能(AI)常见面试题及答案汇总
  • Java 后端高效对接 Python 微调大模型的四种交互方案与实战
  • 基于 Whisper 的日语自动字幕生成工具实践
  • LLaMA Factory 大模型微调指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online