线程应用 - 中断interrupt详解

时间:2022-07-23
本文章向大家介绍线程应用 - 中断interrupt详解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

有些初学者对中断的概念可能会有些许小误会,比如线程调用Thread.interrupt()方法,就认为线程会被中断,停止执行,其实不是这样的,让我们来看下中断interrupt详解。

一、interrupt方法

源码如下:

public void interrupt() {    //判断是否操作线程
    if (this != Thread.currentThread())
checkAccess();    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {            //只是设置中断标记位
interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}

可以看到interrupt方法并不会对任务终止线程的操作,仅仅只是设置了一个中断的标记位。为了不造成误解,我们看以下示例:

public class InterruptTest {
    public static void main(String[] args) {
        new test().start();
    }
}
class test extends Thread {
    static int n = 10;
    public void run() {
        for (int i = 0; i < 15; i++) {
            if (i == n) {
                System.out.println("线程要被中断了:" + i);
                this.interrupt();
            }
            System.out.println("当前运行数字为:" + i);
        }
    }
}

如果interrupt方法会直接终止线程的话,那么当上述代码中的i为10时,后面就不会再继续执行下去了,运行结果为:

可以看到线程还是运行到了最后。正如源码中所说的那样,调用interrupt仅仅只是做了一个中断标识而已,其余并不会做任何操作。

但是也不能说interrupt方法是完全没有任何作用的,因为interrupt方法对于java来说其实是一个协作机制,调用interrupt方法会把调用线程的中断状态设置为true,而其他需要依赖这个中断符的方法在运行时如果监测到这个中断标志就会作出响应。

下面示例,使用Thread.sleep方法观察运行结果。

public class InterruptTest {
    public static void main(String[] args) {
        new test().start();
    }
}
class test extends Thread {
    static int n = 10;
    public void run() {
        for (int i = 0; i < 15; i++) {
            if (i == n) {
                System.out.println("线程要被中断了:" + i);
                this.interrupt();
                System.out.println("线程调用中断方法:" + i);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
            System.out.println("当前运行数字为:" + i);
        }
    }
}

运行结果:

上述运行过程中每一次循环都会调用Thread.sleep方法,将线程休眠1秒钟,然而当第10次循环,调用interrupt方法后再调用休眠方法则抛出了异常。

这样的情况在Object.wait等方法中也会出现。所以interrupt相当于java的一个协作机制,如果调用了Object.wait或Thread.sleep方法,会判断线程的中断标志位,如果发现他被设置为true后(线程可以调用interrupt方法来修改标志位),则会抛出异常,后续如果线程不想继续被操作,可以利用这个异常来让线程运行退出,比如for循环的break,或者直接return。

二、isInterrupted方法

public boolean isInterrupted() {
    return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);

检测线程是否中断方法,如果当前线程已经中断则返回true,否则返回false。继续使用上述例子,观察结果:

public class InterruptTest {
    public static void main(String[] args) {
        new test().start();
    }
}
class test extends Thread {
    static int n = 10;
    public void run() {
        for (int i = 0; i < 15; i++) {
            if (i == n) {
                System.out.println("线程要被中断了:" + i);
                this.interrupt();
                System.out.println("线程调用中断方法:" + i);
                boolean flag = this.isInterrupted();
                System.out.println("线程是否被中断:" + flag);
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
            System.out.println("当前运行数字为:" + i);
        }
    }
}

运行结果:

结果发现,线程是否被中断检测方法返回了true。

三、interrupted方法

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

interrupted方法是线程类中的静态方法,在api文档中的说明为返回并清除中断状态。

使用上述例子并将isInterrupted方法替换为interrupted方法。观察结果:

public class InterruptTest {
    public static void main(String[] args) {
        new test().start();
    }
}
class test extends Thread {
    static int n = 10;
    public void run() {
        for (int i = 0; i < 15; i++) {
            if (i == n) {
                System.out.println("线程要被中断了:" + i);
                this.interrupt();
                System.out.println("线程调用中断方法:" + i);
                boolean flag = Thread.interrupted();
                System.out.println("线程是否被中断:" + flag);
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
            System.out.println("当前运行数字为:" + i);
        }
    }
}

运行结果:

上述结果发现,线程在调用Thread.sleep后并没有被中断。加入isInterrupted方法观察线程中断标志位情况:

运行结果说明调用中断方法后调用Thread.sleep方法,没有中断的原因是因为调用了interrupted方法,将中断标志位重置为了false。而interrupted方法返回了true是因为,在重置之前,他的中断标志位是正常的。

四、总结

上述测试和分析了以后对这三个方法应该就比较清晰了。

(1)interrupt方法其实是修改中断标记位为true,起到一个协助的作用,但是并不会真正的终止线程。

(2)isInterrupted方法最纯粹,就是判断当前线程是否有中断标记位,返回结果为true或false。

(3)interrupted方法是一个静态方法,返回的是调用方法前的中断标记位,并清除中断标记位为false。