zoukankan      html  css  js  c++  java
  • 关于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============================

    CSDN博客地址:https://blog.csdn.net/qq_34115899
  • 相关阅读:
    kubernetes-handbook 阅读笔记
    kubernetes-notes--阅读笔记
    SpringInAction4笔记——复习
    spring源码解析——2容器的基本实现(第2版笔记)
    把node加入master节点时,日志内容分析
    初始化master节点时,日志内容分析
    Mac OS用minikube安装单节点kubernetes
    Mac OS用vmvare安装多节点kubernetes
    FatMouse's Speed 基础DP
    FatMouse and Cheese 动态化搜索
  • 原文地址:https://www.cnblogs.com/lcy0515/p/10807891.html
Copyright © 2011-2022 走看看