synchronized加锁方法反编译后,同步方法表现为acc_synchronized标志位,同步代码块则呈现monitorenter与monitorexit指令成对出现,且异常出口处必有额外monitorexit确保锁释放。

synchronized加锁的方法在反编译为格式化字节码后,会呈现出明确、可识别的指令模式和标记特征,主要取决于它是作用于方法还是代码块。
同步方法:ACC_SYNCHRONIZED 标志位
当 synchronized 修饰一个普通方法或静态方法时,编译器不会插入 monitorenter/monitorexit 指令,而是在方法的访问标志(access flags)中设置 ACC_SYNCHRONIZED 位。
- 使用
javap -v查看字节码时,该方法的 flags 行会显式包含ACC_SYNCHRONIZED - JVM 执行时,遇到带此标志的方法,会自动在入口处尝试获取对应锁(this 或 Class 对象),并在方法返回(无论正常 return 还是异常抛出)时自动释放
- 这种实现是隐式的,字节码中看不到 monitor 相关指令,但语义由 JVM 运行时强制保障
同步代码块:monitorenter 和 monitorexit 成对出现
对于 synchronized(obj) { ... } 这种写法,编译器会生成明确的字节码指令:
- 在同步区域起始位置插入
monitorenter指令 - 在正常执行结束位置插入
monitorexit指令 - 在每个可能抛出异常的出口(如 catch 前、finally 入口)额外插入一条
monitorexit,确保锁必定释放 - 因此你会看到
monitorenter后紧跟一到多个monitorexit,且至少有一对出现在 try-catch 结构的异常表(Exception table)中
锁对象在字节码中的体现
同步代码块的锁对象(如 synchronized(this) 或 synchronized(lock))会以操作数栈方式加载:
- 通常先用
aload_0(this)、aload_1(局部变量)等指令把锁对象压栈 - 紧接着就是
monitorenter,它从栈顶弹出一个引用类型值作为 monitor 目标 - 所以观察字节码时,
monitorenter前必有对应对象的加载指令
无锁/轻量级锁不改变字节码结构
锁升级(偏向→轻量→重量)是 JVM 运行时在对象头(Mark Word)和 Monitor 中完成的优化,完全不反映在字节码层面:
- 同一段 synchronized 代码,无论实际走的是偏向锁还是重量级锁,反编译出的字节码完全一致
- 字节码只定义“要加锁”,不规定“怎么加”;具体锁形态由 JVM 根据竞争情况动态决定
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











