synchronized关键字编译后不生成专属字节码指令,而是根据场景生成monitorenter/monitorexit指令(同步代码块)或设置ACC_SYNCHRONIZED标志(同步方法),均依赖JVM的monitor机制实现锁语义。

synchronized 关键字在编译后不会直接生成某一条专属字节码指令,而是根据使用场景(同步代码块 or 同步方法)被编译为不同的字节码结构:主要是 monitorenter / monitorexit 指令(用于同步代码块),或通过方法访问标志 ACC_SYNCHRONIZED(用于同步方法)来实现锁语义。
同步代码块:插入 monitorenter 和 monitorexit
当你写:
立即学习“Java免费学习笔记(深入)”;
synchronized(obj) {doSomething();
}
编译器会在字节码中:
- 在进入同步块前插入 monitorenter 指令(尝试获取 obj 的 monitor 锁)
- 在正常退出和异常退出路径上,都插入 monitorexit 指令(释放锁)
- 为保证异常安全,编译器会生成多个 monitorexit,通常配合异常表(exception table)覆盖所有可能的出口
同步方法:设置 ACC_SYNCHRONIZED 标志位
当你写:
立即学习“Java免费学习笔记(深入)”;
public synchronized void foo() {doSomething();
}
编译器不会在方法体中插入 monitorenter/monitorexit,而是:
- 在方法的 access_flags 中设置 ACC_SYNCHRONIZED 位
- JVM 在执行该方法前自动执行 monitorenter(锁当前对象或 Class 对象)
- 在方法返回(包括正常 return 或抛出异常)时自动执行 monitorexit
底层依赖:monitor 锁机制
无论哪种形式,最终都依赖 JVM 的 monitor 实现(通常基于操作系统互斥量或自旋+队列):
- 每个 Java 对象头(Object Header)中隐含一个 monitor 引用(在锁膨胀后指向真正的 monitor 结构)
- monitorenter 尝试将线程与该 monitor 关联;若已被占用,则阻塞或自旋
- monitorexit 释放 monitor,并唤醒等待队列中的一个线程(如有)
验证方式:用 javap 查看字节码
执行 javac Test.java && javap -v Test 可观察到:
- 同步代码块 → 方法 code 属性中出现
monitorenter和monitorexit - 同步方法 → 方法描述行包含
ACC_SYNCHRONIZED,且 code 区无显式锁指令 - 同步静态方法 → 同样标记 ACC_SYNCHRONIZED,但锁的是当前 Class 对象


















