synchronized在发生异常时会自动释放锁,无论抛出unchecked异常、Error还是线程中断,JVM均通过monitorenter/monitorexit指令确保锁释放,避免死锁且保障内存可见性。

synchronized 在发生异常时会自动释放锁,这是它最可靠、最不易出错的特性之一。无论同步代码块或方法中是否抛出异常(包括 unchecked 异常如 NullPointerException、ArrayIndexOutOfBoundsException,甚至 Error 如 OutOfMemoryError),JVM 都会确保锁被正确释放,不会造成死锁或资源永久占用。
异常发生时锁一定会释放
底层通过字节码指令 monitorenter 和 monitorexit 实现:synchronized 块编译后,JVM 会在正常退出路径和所有异常出口处插入 monitorexit 指令(借助异常表机制)。这意味着——
- 即使未写 try-catch,异常向上抛出,锁仍释放
- 即使抛出的是 RuntimeException 或 Error,锁也释放
- 线程在同步块内中断(InterruptedException)或主动 return,锁同样释放
不会因异常导致锁泄漏
这是 synchronized 区别于手动 Lock.lock()/unlock() 的关键优势。使用 ReentrantLock 时若忘记在 finally 中调用 unlock(),就可能引发死锁;而 synchronized 完全规避了这种人为失误风险。
- 无需额外 try-finally 包裹
- 不依赖开发者编码习惯,由 JVM 保障语义完整性
- 适用于任何异常场景,包括不可恢复的 Error
异常不影响锁的互斥性和可见性保证
异常发生前对共享变量的修改,在锁释放时仍遵循 Java 内存模型规则:
立即学习“Java免费学习笔记(深入)”;
- 线程释放锁前,会将工作内存中修改的变量刷新回主内存(保证可见性)
- 下一个获取该锁的线程,会清空本地缓存并重新从主内存读取最新值
- 即使方法中途抛出异常,已执行的赋值、更新等操作依然对其他线程可见(只要发生在 unlock 前)
注意:异常本身不传播锁状态
synchronized 不处理、不捕获、不改变异常行为——它只负责锁管理:
- 异常仍按常规方式向调用栈上层传播
- 锁对象本身不会“记住”曾发生过异常
- 下一次进入同步块时,仍是干净的 Monitor 状态,无残留影响


















