synchronized异常时不会死锁是因为jvm为每个同步块生成两个monitorexit指令:一个在正常退出路径,一个在异常处理器中,确保无论正常结束还是抛出未捕获异常,monitor计数器都能减至零并释放锁。

synchronized 通过 monitorexit 指令释放锁,这是 JVM 在字节码层面强制保证的机制,无论代码正常结束还是中途抛出异常,锁都会被安全释放。
monitorexit 的触发时机
只要线程离开 synchronized 作用域,JVM 就会插入并执行 monitorexit 指令。具体包括:
- 同步代码块执行完毕(到达右大括号
}) - 同步方法执行返回(
return或自然结束) - 在同步块内发生未捕获异常(如
RuntimeException),JVM 会跳转到异常处理路径,仍执行 monitorexit
为什么异常时也不会死锁
JVM 编译器为每个 synchronized 代码块生成两个 monitorexit 指令:一个放在正常退出路径末尾,另一个放在异常处理器(exception handler)中。这样确保:
- 即使抛出异常、提前跳出,锁也能被释放
- 不会因忘记释放而导致其他线程永久阻塞
- 符合“自动资源管理”语义,无需手动干预
底层依赖 Monitor 计数器
monitorexit 的实际效果是操作对象关联的 Monitor 中的计数器(_count):
- 每次进入 synchronized(monitorenter)时,计数器 +1
- 每次退出(monitorexit)时,计数器 −1
- 当计数器归零,Monitor 的 _owner 字段被置为 null,锁才真正释放
- 可重入场景下,同一线程多次进入,需对应次数的 monitorexit 才能完全释放
同步方法的特殊处理
同步方法不显式出现 monitorenter/monitorexit 指令,而是靠方法标志 ACC_SYNCHRONIZED 触发 JVM 自动插入锁逻辑:
- 方法入口隐式执行 monitorenter
- 方法出口(含正常返回和异常抛出)隐式执行 monitorexit
- 行为与同步代码块一致,只是字节码表现形式不同
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











