interrupt、interrupted 、isInterrupted 区别

旧巷老猫 提交于 2020-02-17 05:29:05

interrupt、interrupted 、isInterrupted 区别

参考链接:

https://blog.csdn.net/z69183787/article/details/25076033

https://blog.csdn.net/zhuyong7/article/details/80852884

《并发编程的艺术》

1、 interrupt

interrupt方法用于中断线程。调用该方法的线程的状态为将被置为"中断"状态

注意:
线程中断仅仅是设置线程中一个boolean类型的标志符为True,意味着为中断状态(该字段并不是Thread类的字段,并且标志该字段的方法是native方法),并不会停止线程。需要用户自己去监视线程的状态为并做处理。
支持线程中断的方法,如wait、sleep、join(中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,该线程会立即被唤醒,并抛出中断异常。

从Java的API中可以看到,许多声明抛出InterruptedException的方法(例如Thread.sleep(longmillis)方法)这些方法在抛出InterruptedException之前,Java虚拟机会先将该线程的中断标识位清除,然后抛出InterruptedException,此时调用isInterrupted()方法将会返回false。

2、 interrupted 和 isInterrupted底层实现

2.1 interrupted

  • 测试当前线程是否已经中断。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,第一次返回true,第二次返回false。(注意当前线程为调用该命令的线程环境,不一定是调用该方法的对象,也并不一定是main线程)

  • 为Thread的静态方法,一般Thread.interrupted()即可(也可以用自己创建的对象来调用,效果相同,但一般不这么做,容易给代码的阅读增加复杂度)。 
    扩展:静态方法不能被重写,但是继承该类的类还是可以重新定义该方法,但是不具有多态特性。https://blog.csdn.net/gao_zhennan/article/details/72892946
    https://blog.csdn.net/ghgzczxcvxv/article/details/43966243

实现:

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

2.2 isInterrupted

  • 测试调用该方法的对象是否已经中断。线程的中断状态不受该方法的影响。

  • 为实例方法,由创建的线程对象,或者thread.currentThread()来调用。

实现:

public boolean isInterrupted() {
    return isInterrupted(ClearInterrupted: false)
}

2.3 对比

  1. interrupted 是作用于当前线程,isInterrupted 是作用于调用该方法的线程对象所对应的线程。(线程对象对应的线程不一定是当前运行的线程。例如我们可以在A线程中去调用B线程对象的isInterrupted方法。)

  2. 这两个方法最终都会调用同一个方法,只不过参数一个是true,一个是false。只有当前线程才能清除自己的中断位(对应interrupted()方法)

    先来看一看被调用的方法 isInterrupted(boolean arg)的定义:
    private native boolean isInterrupted( boolean ClearInterrupted); 原来这是一个本地方法,看不到源码。不过没关系,通过参数名我们就能知道,这个参数代表是否要清除状态位。
    如果这个参数为true,说明返回线程的状态位后,要清掉原来的状态位(恢复成原来情况)。这个参数为false,就是直接返回线程的状态位。

3、 实例解析

1.

public static void main(String[] args){ 
    MyThread myThread = new MyThread();
    myThread.start();
    myThread.interrupt();
    System.out.println("第一次返回值:"+Thread.interrupted());
    System.out.println("第二次返回值:"+Thread.interrupted());
}

结果: false false

中断的线程是自己创建的myThread线程,调用的interrupted()是判断当前线程的中断状态,当前线程是main线程,我根本没有中断过main线程,所以2次调用均返回“false”

2.

public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.start();
    Thread.currentThread().interrupt();
    System.out.println("第一次返回值:"+Thread.interrupted());
    System.out.println("第二次返回值:"+Thread.interrupted());
}

结果: true false

Thread.currentThread().interrupt()将当前线程main线程设置为中断状态,所以第1次调用结果返回“true”。 由源码可知interrupted()会重置中断状态,所以第一次调用之后把中断状态给重置了,从中断状态重置为非中断状态,所以第2次调用的结果返回“false”

3.

public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.start();
    myThread.interrupt();
    System.out.println("第一次返回值:"+myThread.isInterrupted());
    System.out.println("第二次返回值:"+myThread.isInterrupted());
}

结果: true true

由源码可知isInterrupted()不会重置中断状态,所以第一次调用之后没有把中断状态给重置(从中断状态重置为非中断状态),所以2次调用的结果都是“true”

4.

public static void main(String[] args){ 
    MyThread myThread = new MyThread();
    myThread.start();
    myThread.interrupt();
    System.out.println("第一次返回值:"+Thread.currentThread().isInterrupted());
    System.out.println("第二次返回值:"+Thread.currentThread().isInterrupted());
}

结果:false false

一次调用Thread.currentThread().isInterrupted()等效于Thread.interrupted()
中断的线程是我们自己创建的myThread线程,我调用的isInterrupted(),由上面源码可知是判断执行该方法的对象所表示线程的中断状态,也就是main的中断状态,我压根没有中断main线程,所以理所当然2次调用结果都返回“false”

5.

public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.start();
    Thread.currentThread().interrupt();
    System.out.println("第一次返回值:"+Thread.currentThread().isInterrupted());
    System.out.println("第二次返回值:"+Thread.currentThread().isInterrupted());
}

结果:true true

中断的线程是当前线程(main线程),我调用的isInterrupted(),由上面源码可知是判断执行该方法的对象所表示线程的中断状态,也就是main的中断状态,所以第1次调用结果返回“true”, 
因为源码内部调用isInterrupted() 参数传的false,不会重置main线程的中断状态,所以第2次调用还是返回”true”

6 .

public class Interrupted {
    public static void main(String[] args) throws Exception {
        // sleepThread不停的尝试睡眠
        Thread sleepThread = new Thread(new SleepRunner(), "SleepThread");
        sleepThread.setDaemon(true);
        // busyThread不停的运行
        Thread busyThread = new Thread(new BusyRunner(), "BusyThread");
        busyThread.setDaemon(true);
        sleepThread.start();
        busyThread.start();
        // 休眠5秒,让sleepThread和busyThread充分运行
        TimeUnit.SECONDS.sleep(5);
        sleepThread.interrupt();
        busyThread.interrupt();
        System.out.println("SleepThread interrupted is " + sleepThread.isInterrupted());
        System.out.println("BusyThread interrupted is " + busyThread.isInterrupted());
        // 防止sleepThread和busyThread立刻退出
        SleepUtils.second(2);
    }
    static class SleepRunner implements Runnable {
        @Override
        public void run() {
            while (true) {
            SleepUtils.second(10);
            }
        }
    }
    static class BusyRunner implements Runnable {
        @Override
        public void run() {
            while (true) {
            }
        }
    }
}

结果: 
SleepThread interrupted is false
BusyThread interrupted is true

从结果可以看出,抛出InterruptedException的线程SleepThread,其中断标识位被清除了,而一直忙碌运作的线程BusyThread,中断标识位没有被清除。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!