java中必须将unlock()放在finally块中释放lock,因为try内抛异常会跳过unlock导致死锁;标准写法是lock.lock()在try外,finally中先判断isheldbycurrentthread()再unlock,避免illegalmonitorstateexception。

Java中用try-catch-finally确保Lock安全释放,核心是把unlock()放在finally块里,无论是否抛异常、是否提前return,都能执行释放逻辑。
为什么不能只在try里unlock
如果把lock.unlock()写在try块末尾,一旦中间代码抛出异常且未被捕获,程序会跳过unlock直接进入catch或向上抛出,导致锁永远不被释放——引发死锁或线程饥饿。
标准写法:finally中调用unlock
正确模式如下:
Lock lock = new ReentrantLock();
lock.lock(); // 先加锁
try {
// 业务逻辑(可能抛异常)
doSomething();
} finally {
if (lock.isHeldByCurrentThread()) { // 推荐检查,避免IllegalMonitorStateException
lock.unlock();
}
}
-
lock.lock()必须在try外调用:因为加锁本身也可能失败(如被中断),但通常不在此处处理中断,而是让上层感知;若需响应中断,可用
lock.lockInterruptibly()并捕获InterruptedException - finally里加isHeldByCurrentThread()判断:防止unlock被重复调用,或在未成功加锁时误调用(比如lock()前就return了)
- 不要在catch里unlock:catch只负责异常处理,释放逻辑统一交给finally,避免遗漏分支
使用try-with-resources的替代方案(Java 7+)
如果自定义Lock实现AutoCloseable,可借助try-with-resources自动释放:
try (MyLockWrapper lockWrapper = new MyLockWrapper(lock)) {
doSomething();
} // 自动调用close() → 即unlock()
但JDK原生Lock接口未实现AutoCloseable,需自行包装。日常开发中,标准finally方式更直观、无额外依赖。
常见错误与规避
-
在finally里再次抛异常:若unlock本身因bug抛出异常(极少见),会掩盖try块中的原始异常。可对unlock做空捕获:
try { lock.unlock(); } catch (Exception ignored) {} - lock对象为null时调用unlock:初始化检查或使用Optional包装,避免NPE
- 多个lock嵌套时未按加锁逆序释放:多个Lock应分别配对finally,或封装成资源管理器统一释放
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











