Thread中interrupt、interrupted、isInterrupted方法区别

简介

什么是中断?

1、比如现在下载一个几百兆的视频,这时候要去下载另一个文件,暂停这个视频,那就是中断该线程,但是这种状态是阻塞的

2、那么想要改变阻塞的状态,通常在线程sleep、wait、join的情况下可以使用中断

3、由于中断可以捕获,通过这种方式可以终结线程

4、中断不是线程结束,只是发送一个 中断信号而已,线程退出还要手动加上自己的线程结束操作

中断分为两种,一种可中断的阻塞,一种不可中断的阻塞

一、interrupt方法

将线程置为中断状态

需要注意的点:线程中断只是改变线程中断状态位,不会停止线程。

需要用户线程自己监视线程的状态位并作出相应的处理。支持线程中断的方法(线程中断后会抛出interruptedException异常)

就是在监视线程的中断状态,一旦线程被置为中断状态,就会抛出中断异常

本线程中断自己是被允许的。

其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。

如果本线程是处于阻塞状态:调用线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也会让它进入阻塞状态。

若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;

调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。

如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时;线程的中断标记会被设置为true,并且它会立即从选择操作中返回。

如果不属于前面所说的情况,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”。

中断一个“已终止的线程”不会产生任何操作。

 public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
 // Just to set the interrupt flag ,native方法
                interrupt0();          
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

二、interrupted方法 (静态方法)

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

interrupted方法作用于当前线程currentThread,isInterrupted是调用该方法的线程对象所对应的线程(A可以调用B线程对象的isInterrupted方法)

三、isInterrupted方法

public boolean isInterrupted() {
        return isInterrupted(false);
    }

该方法都调用了底层的native isInterrupted方法,只是方法一个为true,一个为false。

可以看到 ClearInterrupted 这个参数,代表是清除中断状态

如果参数为true,返回线程状态位,清楚中断状态。参数为false,直接返回

四、sleep、wait方法对中断的处理

Thread类的sleep(),wait()等方法,在接收到interrupt()方法中断时,会抛出异常,同时会将中断标志置为false,如果确实需要中断该线程,则应该在捕捉到异常后,继续调用interrupt()方法进行中断。

为什么不在异常时直接中断线程呢?主要是为了防止线程的资源没有得到释放而中断了线程

比如以下

import java.util.concurrent.TimeUnit;

public class Demo {
    public static void main(String[] args) {
        Object obj = new Object();
        Thread thread = new Thread(new Test(obj), "thread-1");
        thread.start();
        try {
            TimeUnit.MILLISECONDS.sleep(1);
            //2、抛出java.lang.InterruptedException
            thread.interrupt();
            TimeUnit.MILLISECONDS.sleep(1);
            thread.interrupt();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    static class Test implements Runnable {
        Object obj;
        public Test(Object obj) {
            this.obj = obj;
        }
        @Override
        public void run() {
            synchronized(obj) {
                try {
                    //1、首先输出该句(thread-1 before wait)
                    System.out.println(Thread.currentThread().getName() + " before wait");
                    obj.wait();
                    //3、输出Thread[thread-1,5,main],wait interrupte :false
                    System.out.println(Thread.currentThread().getName() + " after wait");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread() + ",wait interrupted :" + Thread.currentThread().isInterrupted());
                }
            }
            try {
                //4、输出thread-1 before sleep
                System.out.println(Thread.currentThread().getName() + " before sleep");
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " after sleep");
            } catch (InterruptedException e) {
                e.printStackTrace();
                //5、输出Thread[thread-1,5,main],sleep interrupte :false
                System.out.println(Thread.currentThread() + ",sleep interrupted :" + Thread.currentThread().isInterrupted());

            }
            //6、输出end
            System.out.println("end");
        }
    }
}

中断会使这些方法从阻塞状态中提前返回,并且在抛出异常是清除了中断状态

那么想要重新设置中断状态可以在catch中重新设置中断。

总结:

1、interrupt()是用来设置中断状态的,isInterrupted()只是简单的查询中断状态,不会对状态进行修改

2、中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。

有些方法,例如 Thread.sleep(),很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法可以轮询中断状态,并在被中断的时候提前返回。 您可以随意忽略中断请求,但是这样做的话会影响响应。

3、当另一个线程通过调用 Thread.interrupt() 中断一个线程时,会出现以下两种情况之一
1. 那个线程在执行一个低级可中断阻塞方法,例如 Thread.sleep()、 Thread.join() 或 Object.wait(),那么它将取消阻塞并抛出 InterruptedException. 因为这些阻塞方法,由于无法预测什么时间会结束,因此需要一种中断机制来进行通知该线程的调用者,让调用者明白该线程已经发生中断并且提前返回.
注意:这些方法会在异常抛出的时候会清除当前线程的中断状态wait()方法的源码看一下就可以了


 

猜你喜欢

转载自blog.csdn.net/weixin_39082432/article/details/105881048
今日推荐