0

0

详解synchronized的MonitorEnter与MonitorExit字节码指令

P粉602998670

P粉602998670

发布时间:2026-02-22 15:13:03

|

818人浏览过

|

来源于php中文网

原创

monitorenter和monitorexit是jvm底层字节码指令,分别负责获取和释放对象锁,通过对象头mark word与objectmonitor协作实现可重入、异常安全的同步机制。

详解synchronized的monitorenter与monitorexit字节码指令

monitorenter 和 monitorexit 到底在干啥

它们不是 Java 代码里的函数,而是 JVM 执行同步块时插入的底层字节码指令——monitorenter 负责“抢锁”,monitorexit 负责“放锁”。你写 synchronized(obj) { ... },编译器就自动给你包上这一对指令;它不关心 obj 是不是 null、是不是 final,只认这个引用值。

关键点在于:锁的归属和计数全靠对象头里的 mark word 和关联的 ObjectMonitor 结构维护,而这两条指令就是触发这套机制的开关。

  • monitorenter 执行时,JVM 检查目标对象是否已被当前线程持有;如果是,计数器 +1(可重入);如果不是,尝试获取锁,失败则进 EntryList 阻塞
  • monitorexit 每执行一次,计数器 -1;只有计数器归零时,锁才真正释放,其他线程才可能被唤醒
  • 哪怕同步块里抛了未捕获异常,JVM 也保证至少有一个 monitorexit 执行——这是通过字节码里的 Exception table 实现的,不是 try-finally 编译出来的

为什么 javap 看到两个 monitorexit?

因为安全。一个给正常流程用,一个专为异常兜底——你看 javap -v 输出,总能看到类似这样的结构:

  0: aload_0
  1: dup
  2: astore_1
  3: monitorenter
  4: getstatic     #2
  7: ldc           #3
  9: invokevirtual #4
 12: aload_1
 13: monitorexit   <-- 正常出口
 14: goto          22
 17: astore_2
 18: aload_1
 19: monitorexit   <-- 异常出口
 20: aload_2
 21: athrow
 22: return
Exception table:
   from    to  target type
       4    14    17   any
      17    20    17   any

没这个双保险,一旦同步块里 NPE 或 OOM,锁就永远卡住——这比性能问题更致命。

VisionStory
VisionStory

AI视频、直播、视频播客

下载
  • 别自己手写 monitorenter/monitorexit:它们是 JVM 内部指令,不能直接调用,也不在 Java API 里
  • 不要以为加了 try-catch 就能替代这个机制:JVM 的异常表处理是字节码层的,比 Java 层的异常处理更早、更底层
  • 如果反编译发现只有一个 monitorexit,那基本说明代码路径极简(比如空块),或编译器做了激进优化(少见,JDK 8+ 后基本都保留双出口)

ACC_SYNCHRONIZED 和 monitorenter 的区别在哪

根本不是“两种实现”,而是同一套机制的两种字节码表达形式:ACC_SYNCHRONIZED 是方法级的“快捷方式”,monitorenter/monitorexit 是代码块级的“手动档”。

比如 public synchronized void m() { } 编译后不会出现那两条指令,而是在方法属性里打上 ACC_SYNCHRONIZED 标志;JVM 运行时看到这个标志,会自动在方法入口插 monitorenter,出口插 monitorexit(同样带异常兜底)。

  • 静态同步方法锁的是 Class 对象,实例方法锁的是 this,但底层都是对某个对象执行 monitorenter
  • ACC_SYNCHRONIZED 方法无法指定锁对象,灵活性不如代码块;但少了显式对象引用,字节码更紧凑
  • 二者锁升级路径完全一致(偏向锁 → 轻量级锁 → 重量级锁),因为最终都落到同一个 ObjectMonitor 实例上

容易被忽略的坑:null、锁对象生命周期、锁粒度

monitorenter 遇到 null 会直接抛 NullPointerException,而且是在字节码执行阶段——不是进入方法后才检查。这意味着,如果你传了个可能为 null 的锁对象,NPE 会发生在同步块第一行之前,且无法被该块内的 catch 捕获。

  • 永远不要用可能为 null 的变量做锁对象,比如 synchronized(map.get("key")) —— 万一 key 不存在,map.get 返回 null,直接炸
  • 锁对象要是长期稳定存在的;比如用局部 new 出来的 new Object() 当锁,每次调用都新建,等于没锁
  • 锁粒度要匹配场景:锁 this 可能导致整个对象被串行化;锁内部私有 final 字段(如 private final Object lock = new Object())才是常见安全做法
  • monitor 的重量级状态(即真正调用 OS mutex)一旦触发,线程挂起/唤醒开销极大;高频短临界区反而比无锁原子操作慢得多

Monitor 不是黑盒,它是 C++ 实现的、和操作系统线程强绑定的结构;看懂 monitorentermonitorexit 的行为,等于摸到了 synchronized 的脉门——其它所有优化(锁消除、锁粗化、自旋)都是在这个基础上叠的。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

246

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

826

2024.03.01

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

183

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

120

2025.11.27

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

686

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

22

2025.12.06

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

695

2023.08.10

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

928

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 5.9万人学习

Sass 教程
Sass 教程

共14课时 | 0.9万人学习

Pandas 教程
Pandas 教程

共15课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号