使用reentrantlock时必须用try-finally确保锁释放:lock()后立即进try块,unlock()置于finally中;其他方式如catch释放、isheldbycurrentthread判断或try-with-resources均不可靠。

使用 ReentrantLock 时,若在临界区发生异常且未正确释放锁,会导致锁被永久持有(即“锁残留”),其他线程将无限阻塞。解决核心是:**确保无论是否异常,锁都必须释放**——这只能靠 try-finally 保障。
必须用 try-finally 包裹 lock() 和 unlock()
lock() 后立即进入 try 块,unlock() 必须放在 finally 中。这是唯一可靠方式,try-with-resources 不适用(ReentrantLock 不实现 AutoCloseable)。
示例:
ReentrantLock lock = new ReentrantLock();
lock.lock(); // 获取锁
try {
// 临界区操作(可能抛异常)
doSomethingDangerous();
} finally {
lock.unlock(); // 无论成功或异常,这里一定执行
}
避免在 lock() 前或 unlock() 后出现异常干扰流程
虽然 lock() 本身极少抛异常(仅当使用带中断语义的 lockInterruptibly() 且线程被中断时),但为严谨起见:
- 若用
lockInterruptibly(),需捕获InterruptedException并妥善处理(如恢复中断状态或退出) -
unlock()在未加锁时调用会抛IllegalMonitorStateException,所以不能随意调用——必须确保只在已成功加锁后才进finally块释放 - 不要把
lock()放在try内:否则加锁失败时finally里的unlock()会出错
可选:使用显式布尔标记判断是否已加锁
极少数场景(如锁获取逻辑复杂、含重试或条件判断),可借助布尔变量辅助判断是否需要释放:
ReentrantLock lock = new ReentrantLock();
boolean locked = false;
try {
lock.lock();
locked = true;
doSomethingDangerous();
} finally {
if (locked) {
lock.unlock();
}
}
该写法更防御,但多数情况下直接用标准 try-finally 更简洁清晰。
不推荐依赖 lock.tryLock() + 超时来规避残留
tryLock(long, TimeUnit) 可防死等,但不解决残留问题——它只是不阻塞地获取锁;一旦获取成功,仍需靠 try-finally 保证释放。超时失败只是避免等待,不是释放兜底机制。
常见误区:
- 在
catch中释放锁,而忽略finally→ 异常未被捕获(如Error或未声明的运行时异常)时仍会残留 - 用
if (lock.isHeldByCurrentThread())判断再释放 → 多余且不可靠,isHeldByCurrentThread()是诊断用,不应作为释放前提
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











