关于interrupt(),interrupted(),isInterrupted()用法分析

我想代码是非常容易解释这个问题的了。下文会给出总结。

总结点击这里或者往下阅读:


直接来一段小代码吧:

public class Interrupt {
    public static void main(String[] args) {
        Thread t = new Thread(new Worker());
        t.start();

        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        t.interrupt();
        System.out.println("Main thread stopped.");
    }

    public static class Worker implements Runnable {

        public void run() {
            System.out.println("Worker started.");
            boolean f; // 用于检测interrupted()第一次返回值
            int i = 0;
            Thread c = Thread.currentThread();
            System.out.println("while之前线程中断状态isInterrupted():" + c.isInterrupted());
            while (!(f = Thread.interrupted())) {// 判断是否中断,如果中断,那么跳出并清除中断标志位
                // 一旦检测到中断,interrupted()第一次返回true,就可以跳出循环,第二次以及以后都是返回false
                System.out.println("while内,还没中断,interrupted()返回值为:" + f);
                System.out.println(c.getName() + "  " + i++ + "  " + c.isInterrupted());
            }
            System.out.println("跳出循环即第一次中断interrupted()返回值:" + f);
            System.out.println("while之后线程中断状态isInterrupted():" + c.isInterrupted()); // 为false,因为interrupt()会清除中断标志位,显示为未中断
            System.out.println("第二次及以后的interrupted()返回值:" + Thread.interrupted());
            c.interrupt();
            System.out.println("再次中断后查询中断状态isInterrupted():" + c.isInterrupted());
            System.out.println("Worker stopped.");
        }
    }
}

运行结果:

....................省略一些相同步骤 

分析说明:

interrupt()是用于中断线程的,调用该方法的线程的状态将被置为"中断"状态。注意:线程中断仅仅是设置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。这里可以看到中断后该线程还在继续往下执行,并没有强制终止线程。

为什么主线程执行t.interrupt()后再调用isInterrupt()返回false??

        因为这里调用interrupted()会清除中断标志位。

还有一种情况:如果线程在wait, sleep,join的时候受阻,调用了interrupt()方法,那么不仅会清除中断标志位,还会抛出InterruptedException异常。下文最后会给出这个例子。

来看看interrupted()和isInterrupted()实现

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

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

private native boolean isInterrupted(boolean ClearInterrupted);  

这是一个native方法,看不到源码,但是注释说明,如果传入false,则不会清除中断标志位,如果传入true,则会清除中断标志位。

isInterrupted ()很老实,只查询中断标志位,不改变中断标志位。

 

==============================================================================

如果线程在wait, sleep,join的时候受阻,调用了interrupt()方法,那么不仅会清除中断标志位,还会抛出 InterruptedException异常。

那么再给出一个例子。

public class Interrupt {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new Worker());
        t.start();

        Thread.sleep(100);
        t.interrupt();

        System.out.println("Main thread stopped.");
    }

    public static class Worker implements Runnable {
        public void run() {
            System.out.println("Worker started.");

            try {
                Thread.sleep(500); // 此时被interrupt()会抛出InterruptedException
            } catch (InterruptedException e) {
                Thread thread = Thread.currentThread();
                System.out.println("再次中断之前isInterrupted():" + thread.isInterrupted());
                System.out.println("再次中断之前interrupted():" + Thread.interrupted());
                // 再次调用interrupt方法中断自己,将中断状态设置为“中断”
                thread.interrupt();
                System.out.println("再次interrupt()后isInterrupted():" + thread.isInterrupted());
                System.out.println("再次interrupt()后第一次interrupted()返回:" + Thread.interrupted());// clear status
                // interrupted()判断是否中断,还会清除中断标志位
                System.out.println("interrupted()后此时再判断IsInterrupted: " + thread.isInterrupted());
                System.out.println("---------After Interrupt Status Cleared----------");
                System.out.println("再次interrupt()后第二次interrupted()返回: " + Thread.interrupted());
                System.out.println("此时再判断IsInterrupted: " + thread.isInterrupted());
            }
            System.out.println("Worker stopped.");
        }
    }
}

运行结果:

总结:

interrupt()方法

  如果不会中断sleep,wait,join方法或文档描述的其他情况,就不会抛InterruptException异常,就不会清除中断标志位,isInterrupt()返回true。

  如果中断sleep,wait,join等,就会抛InterruptException异常,就会清除中断标志位,isInterrupt()返回false。

interrupted()方法

  第一次使用返回true,并清除中断标志位,在此之后查询中断状态isInterrupt()都会返回false,刚刚第一个例子也看到了,利用    第一次返回的true可以跳出循环。第二次以及以后都是返回false。

isInterrupted()方法

  仅仅查询中断标志位来判断是否发生中断并返回true或者false。

 

  如果中断sleep,wait,join等,就会抛InterruptException异常,就会清除中断标志位,那么这种情况应该怎么处理呢?为了保证数据的一致性和完整性,我们需要用Thread.interrupt()方法再次中断自己,置上中断标志位。例子如下:

public class test {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread() {
            public void run() {
                while (true) {
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("Interruted!");
                        break;
                    }
                    try {
                        Thread.sleep(2000); // 睡眠时中断会清除中断标志位
                    } catch (InterruptedException e) {
                        // 如果少了下面这句,这个线程虽然在外面中断,但是只要中断睡眠中的进程
                        // 就会清除中断标志位,仍然处于无限循环,会竞争CPU资源
                        Thread.currentThread().interrupt(); // 再次中断置上中断标记
                    }
                    Thread.yield();
                }
            }
        };
        t1.start();
        Thread.sleep(200);
        t1.interrupt();
    }
}

Thread.sleep()方法由于中断而抛出异常,此时,它会清除中断标记,如果不加处理,那么在下一次循环开始时,就无法捕获这个中断,故在异常处理中,再次设置中断标志位。

 

 

 

接下来给出官方文档说明:

interrupt

public void interrupt()

中断线程。

如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException

如果线程在调用 Object 类的 wait()wait(long) 或 wait(long, int) 方法,或者该类的 join()join(long)join(long, int)sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException

如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException

如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。

如果以前的条件都没有保存,则该线程的中断状态将被设置。

中断一个不处于活动状态的线程不需要任何作用。

抛出:

SecurityException - 如果当前线程无法修改该线程


interrupted

public static boolean interrupted()

测试当前线程是否已经中断。线程的 中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。

返回:

如果当前线程已经中断,则返回 true;否则返回 false

另请参见:

isInterrupted()


isInterrupted

public boolean isInterrupted()

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

线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。

返回:

如果该线程已经中断,则返回 true;否则返回 false

另请参见:

interrupted()

 

==========================Talk is cheap, show me the code============================

posted @ 2018-07-19 15:26  绿叶萌飞  阅读(670)  评论(0编辑  收藏  举报