reentrantlock 的 lock() 不抛检查异常,但 lockinterruptibly() 和 trylock(long, timeunit) 可能抛 interruptedexception;需在 catch 中恢复中断状态、finally 中显式 unlock,并避免阻塞操作与死锁。

ReentrantLock 本身不会在 lock() 时抛出检查异常,但若使用带超时的 tryLock(long, TimeUnit) 或中断敏感的 lockInterruptibly(),就可能遇到 InterruptedException。优雅处理的关键不是“捕获锁获取异常”,而是正确响应中断、避免死锁、及时释放锁,并保持业务逻辑清晰。
用 lockInterruptibly() 响应线程中断
当线程在等待锁时被其他线程中断,lockInterruptibly() 会立即抛出 InterruptedException,而不是继续阻塞。这是协作式中断的体现,适合需要支持取消或超时的场景。
- 必须在
catch块中恢复中断状态(调用Thread.currentThread().interrupt()),否则上层代码无法感知中断意图 - 锁必须在
finally中显式释放,否则一旦抛异常就漏掉unlock() - 示例:
ReentrantLock lock = new ReentrantLock();
try {
lock.lockInterruptibly(); // 可能抛 InterruptedException
// 执行临界区逻辑
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断标志
throw new RuntimeException("操作被中断", e); // 或按需封装/传播
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}用 tryLock() 避免无限等待
不带参数的 tryLock() 立即返回 true 或 false;带超时的版本在指定时间内未获取到锁则返回 false。它们都不抛出 InterruptedException,适合非阻塞或有明确重试策略的场景。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 返回
false表示获取锁失败,不是异常,应作为正常控制流处理 - 可结合退避策略(如指数退避)重试,避免忙等
- 注意:即使
tryLock()成功,仍需在finally中unlock()
统一用 try-finally 保障锁释放
无论用哪种获取方式,只要成功获取了锁(lock()、lockInterruptibly() 或 tryLock() == true),就必须确保最终释放。最可靠的方式是把 unlock() 放在 finally 块中。
- 不要依赖
try-with-resources(ReentrantLock不实现AutoCloseable) - 避免在
catch中提前return而跳过finally—— 这会导致锁泄漏 - 可封装成工具方法,例如:
withLock(lock, () -> { /* 临界区 */ });,内部自动处理获取与释放
避免常见陷阱
很多“锁异常”其实源于误用,而非 API 本身问题。
-
lock()不会抛InterruptedException,但会忽略中断 —— 若线程在阻塞中被中断,它仍会继续等待,直到获取锁后才响应中断(通过Thread.interrupted()检查) - 不要在持有锁时调用可能阻塞的方法(如 I/O、远程调用),否则延长锁占用时间,增加竞争和死锁风险
- 嵌套锁获取务必遵循固定顺序,否则易引发死锁;可借助
tryLock+ 回退机制缓解
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










