monitorenter 和 monitorexit 是 JVM 实现 synchronized 的核心字节码指令,配对出现、嵌套匹配、异常安全:前者获取对象 monitor 锁并支持可重入,后者释放锁;编译器自动插入多点 monitorexit 保障异常时锁正确释放;synchronized 方法则通过 ACC_SYNCHRONIZED 标志隐式加解锁。

monitorenter 和 monitorexit 是 JVM 字节码中实现 synchronized 代码块的核心指令,它们在字节码层面构成“配对出现、嵌套匹配、异常安全”的锁机制基础。
monitorenter:进入临界区的字节码入口
每当编译器遇到 synchronized(obj) { ... } 时,会在同步块起始位置插入 monitorenter 指令。该指令接收一个对象引用(位于操作数栈顶),尝试获取该对象关联的 monitor 锁:
- 若 monitor 未被占用,当前线程直接获得锁,计数器置为 1
- 若已被当前线程持有,则计数器 +1(支持可重入)
- 若被其他线程持有,当前线程阻塞,等待被唤醒并重试
monitorexit:退出临界区的字节码出口
对应每个 monitorenter,编译器保证在同步块所有可能的出口(正常结束、显式 return、异常抛出)前插入 monitorexit 指令:
- 执行时将 monitor 计数器减 1
- 计数器归零后,真正释放锁,唤醒等待队列中的线程
- JVM 规范强制要求:每个
monitorenter必须有且仅有一个匹配的monitorexit(由编译器静态插入,非程序员手写)
异常场景下的自动配对保障
即使同步块内抛出异常,JVM 仍能确保锁被正确释放——编译器会为每个 synchronized 块生成多个 monitorexit,分别置于每个可能的异常出口之后(通过 exception table 关联):
- 例如:try-catch 包裹 synchronized 块时,catch 分支末尾、finally 块开头等位置都可能插入
monitorexit - 这种“多点释放”设计是 JVM 层面的异常安全保证,无需开发者干预
- 可通过
javap -v查看字节码,观察 exception table 中的 handler 范围与对应指令偏移
与 synchronized 方法的区别
synchronized 实例方法不使用 monitorenter/monitorexit 指令,而是通过方法访问标志 ACC_SYNCHRONIZED 实现:
- JVM 在调用该方法前自动执行隐式加锁(this 或 class 对象)
- 方法返回(无论正常或异常)时自动解锁
- 本质仍是 monitor 机制,只是字节码表现形式不同











