可中断锁机制:ReentrantLock的lockInterruptibly解析
定义
ReentrantLock 实现了可中断性,这意味着线程在等待锁的过程中,可以被其他线程中断而提前结束等待。可打断的方法lockInterruptibly() 的行为与 Thread.sleep() 非常相似:
-
和
Thread.sleep()一样,会完全放弃用户态的CPU时间片,让操作系统调度其他线程。这是所有高效阻塞机制(sleep,wait,park,lock等待)的共同核心原则:避免“忙等待”(Busy-Waiting),即在条件不满足时主动让出CPU,而不是空转浪费资源。 -
当线程在等待锁的阻塞过程中被中断,它会立即放弃等待,从阻塞处(
lockInterruptibly()调用点)抛出InterruptedException。
完整流程:
-
线程状态 → 线程因
lock.lockInterruptibly()在 AQS 队列中等待锁,调用LockSupport.park()后进入WAITING状态,并完全放弃 CPU。 -
外部中断 → 另一个线程(如主线程)调用
blockedThread.interrupt()。 -
系统响应 → JVM 与操作系统内核协同,将该线程标记为可运行,并将其状态从
WAITING改为RUNNABLE。 -
进入调度队列 → 线程被放入操作系统的 就绪队列,等待 CPU 调度。
-
获得 CPU 时间片 → 操作系统调度器在某个时刻为此线程分配 CPU 时间片。
-
恢复执行点 → 线程获得 CPU 后,从当初阻塞的
LockSupport.park()之后恢复执行,回到 AQS 框架(如acquireInterruptibly方法)的循环中。 -
检查中断标志 → AQS 代码立即检查线程的中断标志,发现其为
true(表示已被中断)。 -
执行抛出动作 → AQS 代码执行
throw new InterruptedException()。 -
异常传播 →
InterruptedException沿调用栈向上传播,最终跳出lockInterruptibly()方法。 -
用户处理 → 异常被用户代码中的
catch (InterruptedException e)块捕获,线程在 catch 块中执行中断处理逻辑,并彻底放弃对锁的争夺。
import java.util.concurrent.locks.ReentrantLock;
public class LockInterruptiblyDemo {
// 创建一个公平锁,便于观察线程进入等待队列
private static final ReentrantLock lock = new ReentrantLock(true);
public static void main(String[] args) throws InterruptedException {
// 主线程先获取锁,确保后续线程都会阻塞
System.out.println("[主线程] 我先拿到锁。");
lock.lock();
// 创建并启动一个会因等待锁而被阻塞的线程
Thread blockedThread = new Thread(() -> {
try {
System.out.println("[子线程] 尝试通过 lockInterruptibly() 获取锁...");
// 这里会阻塞,等待主线程释放锁
lock.lockInterruptibly(); // 🟢 可中断的阻塞点,类似于 Thread.sleep()
// 正常情况下(未被中断),获取到锁后执行这里
try {
System.out.println("[子线程] 成功获取到锁并开始工作!");
} finally {
lock.unlock();
System.out.println("[子线程] 工作完成,释放锁。");
}
} catch (InterruptedException e) {
// 在等待锁的过程中被中断,会立即跳到这里执行
System.out.println("[子线程] 在等待锁时被中断!放弃等待。");
// 此时线程的中断状态已被清除 (Thread.interrupted() 返回 false)
// 可以在这里做一些资源清理工作
}
});
blockedThread.start();
Thread.sleep(1000); // 确保子线程已经启动并进入AQS等待队列
System.out.println("[主线程] 子线程已阻塞在等待队列中,我现在中断它。");
blockedThread.interrupt(); // 🎯 关键操作:中断子线程
Thread.sleep(500); // 给子线程一点时间处理中断
System.out.println("[主线程] 我释放锁。");
lock.unlock(); // 即使现在释放锁,被中断的子线程也不会来拿了
blockedThread.join(); // 等待子线程完全结束
System.out.println("[主线程] 演示结束。");
}
}
运行上述代码,输出结果如下:
[主线程] 我先拿到锁。
[子线程] 尝试通过 lockInterruptibly() 获取锁...
[主线程] 子线程已阻塞在等待队列中,我现在中断它。
[子线程] 在等待锁时被中断!放弃等待。
[主线程] 我释放锁。
[主线程] 演示结束。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)