必须在 finally 块中调用 unlock(),因为 lock() 不自动释放锁,只有 finally 能确保无论异常、return 或复杂控制流,unlock 都会被执行,避免死锁或线程饥饿。

使用 Lock 接口时,必须在 finally 块中调用 unlock(),这是确保锁被释放的唯一可靠方式。因为 lock() 不像 synchronized 那样自动释放,一旦忘记或异常跳过释放逻辑,就会导致死锁或线程饥饿。
为什么必须用 finally 释放锁
Lock 的获取与释放是手动配对的:调用 lock() 后,必须显式调用 unlock();而该调用可能被异常中断、提前 return 跳过,或在复杂控制流中遗漏。只有 finally 块能保证无论是否抛异常、是否提前返回,unlock 都会被执行。
标准写法:lock + try-finally
正确模式如下:
lock.lock();
try {
// 临界区业务逻辑
// 可能抛出异常、return、continue 等
} finally {
lock.unlock(); // 这里一定会执行
}
常见错误与规避方式
- 把 unlock 放在 try 内部:一旦临界区抛异常且未被捕获,unlock 就不会执行。
- 在 catch 中释放锁,但没写 finally:如果 catch 块本身又 throw 新异常,或包含 return,仍可能跳过 unlock。
- 用 if (lock.isHeldByCurrentThread()) 判断再 unlock:没必要且不安全——Lock 不要求必须由持有线程释放(如 ReentrantLock 允许),且判断本身不是原子操作,反而增加复杂度。
- 在方法出口统一 unlock(无 finally):多个 return 路径容易遗漏,不可靠。
进阶建议:封装为工具方法或使用 try-with-resources
若频繁使用,可封装成自动管理的锁模板,例如:
public static void withLock(Lock lock, Runnable action) {
lock.lock();
try { action.run(); } finally { lock.unlock(); }
}
或者实现 AutoCloseable 的 LockGuard 类,配合 try-with-resources 使用,让编译器强制保障资源清理。

















