中断
N 人看过
字数:1.1k字 | 预计阅读时长:4分钟
在 Core Java 中有这样一句话:”没有任何语言方面的需求要求一个被中断的程序应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断 “ 中断是一种协作机制。
也就是说其他线程调用目标线程的 interrupt 方法,并不会让目标线程停止和提前返回抛出 InterruptedException 表明自己提前返回了,调用 interrupt 方法只是给目标线程设置了一个标志位,友好地提示对方可不可以停止手中的事情提前返回,所以调用 interrupt 的方法产生结果完全是掌握在目标线程手中的,目标线程可以自己定义发现中断标志位 true 后的处理逻辑,是停下手中的事情然后还是不理会标志会继续做自己的事情。
1. 处于 Runnable 状态线程对中断标志位设置为了 true 后续的反应完全由自己决定
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new MyThread();
t.start();
Thread.sleep(1); // 暂停1毫秒
t.interrupt(); // main线程中断目标t线程,只是向目标线程目标标志位interrupt设置为了true而已
t.join(); // 等待t线程结束
System.out.println("end");
}
}
class MyThread extends Thread {
public void run() {
int n = 0;
while (! isInterrupted()) { // 目标线程发现自己中断了,可以选择不理会继续执行任务,也可以选择停止手中的任务提前返回抛出InterruptedException
n ++;
System.out.println(n + " hello!");
}
}
}
class MyThread extends Thread {
public void run() {
int n = 0;
while (true) { // 目标线程发现自己中断了,可以选择不理会继续执行任务,也可以选择停止手中的任务提前返回抛出InterruptedException
n ++;
System.out.println(n + " hello!");
}
}
}
2.处于 sleep 以及 wait 状态的线程对于中断标志位设置成了 true,中断发生会被唤醒,后续是否立刻相应中断以及何时响应中断由你自己决定(需要捕捉 InterruptedException)
实例代码
Thread t = new Thread (){
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//exception被捕获,但是为输出为false 因为标志位会被清空
System.out.println(isInterrupted());
}
}
};
t.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
t.interrupt();//置为true
这里典型可以参考 AQS 等待队列中的 Node,在独占模式下 Node 被唤醒存在两种原因:
- 被中断唤醒
- 头结点释放到头结点唤醒(该 Node 是等待队列中第一个状态正常的 Node,可能为 Head 的后继结点,后继结点取消就从后向前查找第一个)
当一个 Node 被其他线程调用中断 interpret 将状态标志位设置为 true,该 Node 唤醒后不会第一时间去处理中断,而是会有一个自旋检查前继结点以及状态,直到获取到资源后才会去响应中断,获取资源不成功是不会响应中断的,这期间可能又会进入到 waiting 状态。
public final void acquire(int arg) {
// 独占模式下,每个进入到AQS会首先去尝试获取资源,获取资源失败就会cas自旋入队
// 此处体现了非公平锁,会出现等待队列中还有等待线程,但是一进来的线程去抢占加塞一次
if (!tryAcquire(arg) && // 首先尝试获取资源,获取资源成功返回,获取资源失败,尝试Nodecas自旋入队
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // cas自旋入队成功后,进入等待休息状态
selfInterrupt(); // 获取到资源后acquireQueued才会true,才会响应中断
}
3. 处于 sleep 期间的线程对持有的锁不会进行释放
public class Debug26 {
static ReentrantLock reentrantLock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t = new MyThread1();
t.start();
Thread.sleep(3000); // 主线程暂停3秒目的是为了让线程t抢占到锁
System.out.println(reentrantLock.tryLock()); // 输出false
t.join(); // 等待t线程结束
System.out.println("end");
}
static class MyThread1 extends Thread {
public void run() {
reentrantLock.lock();
try{
Thread.currentThread().wait(10000);
}catch(InterruptedException e){
System.out.println("准备返回了...");
}
}
}
}
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。