ReentrantLock.lockInterruptibly()在等待锁时可响应中断并抛出InterruptedException;它基于AQS的acquireInterruptibly实现,失败后以可中断方式挂起,检测到中断即清理节点并退出;与lock()不同,它不忽略中断,需try-catch配合finally中安全unlock。

ReentrantLock.lockInterruptibly() 的核心在于:它让线程在**等待获取锁的过程中,如果被其他线程调用 interrupt(),会立即抛出 InterruptedException 并退出等待,而不是继续阻塞。
底层依赖 AQS 的可中断独占模式
ReentrantLock 基于 AbstractQueuedSynchronizer(AQS)实现。lockInterruptibly() 调用的是 AQS 的 acquireInterruptibly(int arg) 方法。该方法内部:
- 先尝试快速获取锁(
tryAcquire(arg)),成功则直接返回; - 失败后,将当前线程封装为 Node 加入同步队列,并以**可中断方式**挂起(调用
doAcquireInterruptibly(arg)); -
doAcquireInterruptibly在 park 等待时,会定期检查线程的中断状态;一旦发现被中断,就清理节点、抛出异常,不继续等待。
与 lock() 的关键区别
普通 lock() 在等待锁时对中断“免疫”——即使线程被中断,它仍会在队列中等待,直到获得锁后才响应中断(即中断状态被保留,但不打断等待本身);而 lockInterruptibly() 是“实时响应”中断:
- 中断发生在 尚未获取锁、正在 park 等待时 → 立即抛出
InterruptedException; - 中断发生在 已持有锁之后 → 和普通线程一样,只是设置中断状态,需手动处理;
- 若线程在等待过程中被中断,它不会获得锁,也不会留下残留状态(AQS 会安全地取消该次获取尝试)。
典型使用模式:必须配合 try-catch 并释放锁
因为可能抛异常,所以不能像 lock() 那样简单配对 unlock()。正确写法是:
立即学习“Java免费学习笔记(深入)”;
注意:unlock() 必须放在 finally 块中,且只在 lock 成功后才调用;异常路径下不能 unlock。示例:
ReentrantLock lock = new ReentrantLock();
try {
lock.lockInterruptibly(); // 可能抛 InterruptedException
// 执行临界区操作
} catch (InterruptedException e) {
// 响应中断:恢复中断状态(可选),清理,退出或重试
Thread.currentThread().interrupt(); // 推荐:保持中断信号向上传递
return; // 或 throw new RuntimeException(e);
} finally {
if (lock.isHeldByCurrentThread()) { // 避免未加锁就解锁
lock.unlock();
}
}
实际场景举例
常见于需要支持“限时等待”或“协作式取消”的任务中:
- 线程池中执行带超时的任务(如 Future.cancel(true));
- 交互式应用中用户点击“取消”,主线程 interrupt 工作线程;
- 网络请求等待数据库锁时,连接超时触发中断,避免无限等待。


















