应优先使用lockInterruptibly()当需支持外部中断(如任务取消、优雅关闭),典型场景包括长耗时I/O前的资源准备、定时任务、@Async任务等;它响应interrupt(),抛出InterruptedException,且需在catch中恢复中断状态并确保finally解锁。

在多线程并发中,ReentrantLock.lockInterruptibly() 是一种可中断的加锁方式,它允许线程在等待锁的过程中响应 Thread.interrupt(),从而避免无限期阻塞。相比 lock() 的不可中断特性,lockInterruptibly() 更适合需要可控超时、协作式取消或资源清理的场景。
什么时候该用 lockInterruptibly 而不是 lock
当线程获取锁的过程可能耗时较长,且你希望该线程能被外部主动“叫停”(比如任务被取消、用户请求中断、服务优雅关闭),就应优先考虑 lockInterruptibly()。典型场景包括:长耗时 I/O 前的临界资源准备、定时任务中的锁竞争、Spring 中使用 @Async 或线程池执行的可中断任务等。
- 调用前线程的中断状态为
false,若锁已被占用,线程会进入 WAITING 状态并响应后续中断 - 若调用时线程已被中断,会立即抛出
InterruptedException,不会尝试获取锁 - 成功获取锁后,线程中断状态会被清除(即
Thread.interrupted()返回true并清标志)
基本用法与异常处理要点
必须将 lockInterruptibly() 放在 try 块内,并在 catch(InterruptedException) 中做合理处理——不能简单吞掉异常,也不建议直接忽略中断意图。
- 捕获
InterruptedException后,通常应恢复中断状态(Thread.currentThread().interrupt();),以便上层逻辑感知中断 -
unlock()必须放在finally块中,确保锁一定被释放,即使发生中断或异常 - 不要在
catch块里直接 return 或 throw 新异常而不恢复中断,否则会丢失中断信号
示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
ReentrantLock lock = new ReentrantLock();
try {
lock.lockInterruptibly(); // 可中断地获取锁
// 执行临界区操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
throw new RuntimeException("获取锁被中断", e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
结合 tryLock 与 interrupt 实现更灵活控制
lockInterruptibly() 是阻塞式可中断,但有时你需要“最多等 X 秒,期间可被中断”。这时可组合使用 tryLock(long, TimeUnit) 和手动检查中断状态。
-
tryLock(timeout, unit)本身也响应中断:等待过程中被中断,会提前返回false并抛出InterruptedException - 若用
tryLock()(无参)失败,再决定是否重试或放弃,需自行判断中断状态:Thread.interrupted() - 注意:
tryLock()不响应中断,仅立即返回true/false;只有带超时的版本和lockInterruptibly()才真正支持中断等待
常见误区与注意事项
容易忽略的关键细节会影响中断语义的正确性:
- 不要在持有锁期间长时间执行可能阻塞的操作(如 sleep、wait、I/O),否则中断无法及时生效;应在临界区内只做必要操作
- 如果锁是公平锁(
new ReentrantLock(true)),lockInterruptibly()仍遵循公平策略,但中断优先级高于排队顺序 - 多个线程同时调用
lockInterruptibly(),其中一个被中断后,其余线程仍按队列顺序竞争,不会“跳过”被中断者的位置 - 中断不是“强制释放锁”,而是让等待线程提前退出等待,已持锁线程不受影响,也不会自动 unlock

















