• 线程基础知识07 线程中断机制


    1 简介
    2 通过volatile变量实现
    3 通过原子类实现
    4 Interrupted
      4.1 api
      4.2 简单示例 interrupt()和isInterrupted()
      4.3 示例-证明interrupt()方法不会停止线程
      4.4 调用某个线程的interrupt()方法,若该线程处于阻塞状态    
        4.4.1 示例
        4.4.2 处理上面的问题
      4.5 static interrupted()示例
    5 小结
      5.1 interrupt()方法
      5.2 isInterrupted()
      5.3 static interrupted()

    1 简介

      一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume方法 都已经被废弃了。
      在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的机制——中断。
      中断只是一种协作机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示别的线程要求这条线程中断,此时究竟该做什么需要你自己写代码实现。
      每个线程对象中都有一个标识,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;
      通过调用线程对象的interrupt方法将该线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。

    2 通过volatile变量实现

    static volatile boolean flag = false; //中断标识
    
        public static void main(String[] args) {
    
    
            new Thread(()->{
                while (true){
                    if(!flag){
                        System.out.println("线程正常执行");
                    }else{
                        System.out.println("线程执行结束");
                        break;
                    }
                }
            }).start();
    
            try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(()->{
                flag = true;
            }).start();
        }

    执行结果

    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程执行结束
    
    

    3 通过原子类实现

    static AtomicBoolean flag = new AtomicBoolean(false); //中断标识
    
        public static void main(String[] args) {
    
    
            new Thread(()->{
                while (true){
                    if(!flag.get()){
                        System.out.println("线程正常执行");
                    }else{
                        System.out.println("线程执行结束");
                        break;
                    }
                }
            }).start();
    
            try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(()->{
                flag.set(true);
            }).start();
        }

    4 Interrupted

    4.1 api

     

    4.2 简单示例 interrupt()和isInterrupted()

    interrupt()方法设置中断标志位为true ,isInterrupted()方法获取线程的中断标志位
    public static void main(String[] args) {
    
    
            Thread t1 = new Thread(() -> {
                while (true) {
                    if (!Thread.currentThread().isInterrupted()) {
                        System.out.println("线程正常执行");
                    } else {
                        System.out.println("线程执行结束,t1的中断标识" + Thread.currentThread().isInterrupted());
                        break;
                    }
                }
            });
            
            Thread t2 = new Thread(() -> {
                System.out.println("t1的中断标识------" + t1.isInterrupted());
                t1.interrupt();
                System.out.println("t1的中断标识------" + t1.isInterrupted());
            });
            t1.start();
            t2.start();
        }

    执行结果,在t2中,调用t1.interrupt();只是设置t1的中断标志为true,不会停止t1线程,想要停止t1线程,只能在t1线程中自己编码去停止,这里我是不断的去获取这个标志位,当标志位为true时,停止了线程。

    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    线程正常执行
    t1的中断标识------false
    线程正常执行
    t1的中断标识------true
    线程执行结束,t1的中断标识true
    
    

    4.3 示例-证明interrupt()方法不会停止线程

    public static void main(String[] args) {
    
    
            Thread t1 = new Thread(() -> {
                for (int i = 0;i < 200;i ++){
                    System.out.println("线程执行" + i + "| t1的中断标识为" + Thread.currentThread().isInterrupted());
                }
            });
    
            Thread t2 = new Thread(() -> {
                System.out.println("t1的中断标识------" + t1.isInterrupted());
                try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
                t1.interrupt();
                System.out.println("t1的中断标识------" + t1.isInterrupted());
            });
            t1.start();
            t2.start();
        }

    执行结果,发现,刚开始t1的中断标识是false,到69后面,t1的中断标识变为true了,但是t1线程还是在正常执行。

    说明interrupt()方法只是设置了一个标志位,并不会停止该线程,想要停止线程,需要我们自己编码实现。

    线程执行0| t1的中断标识为false
    线程执行1| t1的中断标识为false
    线程执行2| t1的中断标识为false
    线程执行3| t1的中断标识为false
    线程执行4| t1的中断标识为false
    t1的中断标识------false
    线程执行5| t1的中断标识为false
    线程执行6| t1的中断标识为false
    。。。。。。。。。。。。。。。。
    线程执行69| t1的中断标识为false
    t1的中断标识------true
    线程执行70| t1的中断标识为true
    线程执行71| t1的中断标识为true
    线程执行72| t1的中断标识为true
    线程执行73| t1的中断标识为true
    。。。。。。。。。。。。。。。。
    线程执行195| t1的中断标识为true
    线程执行196| t1的中断标识为true
    线程执行197| t1的中断标识为true
    线程执行198| t1的中断标识为true
    线程执行199| t1的中断标识为true

    4.4 调用某个线程的interrupt()方法,若该线程处于阻塞状态

      如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,interrupt()设置的的true中断标识会被清除,变为false。线程也会退出被阻塞状态,并抛出一个InterruptedException异常,继续执行。

    4.4.1 示例

    在t1线程中调用了sleep方法

    public static void main(String[] args) {
    
    
            Thread t1 = new Thread(() -> {
                for (int i = 0;i < 200;i ++){
                    if(!Thread.currentThread().isInterrupted()){
                        System.out.println("线程执行" + i + "| t1的中断标识为" + Thread.currentThread().isInterrupted());
                        try { 
                            Thread.sleep(2); 
                        } catch (InterruptedException e) {
                            e.printStackTrace(); 
                        }
                    }else{
                        System.out.println("线程结束" + "| t1的中断标识为" + Thread.currentThread().isInterrupted());
                        break;
                    }
    
                }
            });
    
            Thread t2 = new Thread(() -> {
                System.out.println("t1的中断标识------" + t1.isInterrupted());
                try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
                t1.interrupt();
                System.out.println("t1的中断标识------" + t1.isInterrupted());
                try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
            });
            t1.start();
            t2.start();
        }

    执行结果

      最开始,t1的中断标识为false,正常执行

      执行到3时,调用了t1的interrupt()方法,t1的中断标识被设置为true

      但是我们看4这里,t1的中断标识马上变为false

      到了9这里,抛出了InterruptedException异常

      继续正常执行

    线程执行0| t1的中断标识为false
    t1的中断标识------false
    线程执行1| t1的中断标识为false
    线程执行2| t1的中断标识为false
    线程执行3| t1的中断标识为false
    t1的中断标识------true
    线程执行4| t1的中断标识为false
    线程执行5| t1的中断标识为false
    线程执行6| t1的中断标识为false
    线程执行7| t1的中断标识为false
    线程执行8| t1的中断标识为false
    线程执行9| t1的中断标识为false
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at com.ruoyi.weixin.user.MyTest.IntrrupterTest.IntrrupterTest04.lambda$main$0(IntrrupterTest04.java:16)
        at java.lang.Thread.run(Thread.java:748)
    线程执行10| t1的中断标识为false
    线程执行11| t1的中断标识为false
    线程执行12| t1的中断标识为false
    线程执行13| t1的中断标识为false
    线程执行14| t1的中断标识为false
    。。。。。。。。。。。。。。。。。
    线程执行195| t1的中断标识为false
    线程执行196| t1的中断标识为false
    线程执行197| t1的中断标识为false
    线程执行198| t1的中断标识为false
    线程执行199| t1的中断标识为false

    4.4.2 处理上面的问题

    只需要在异常处理中再调用下interrupt()方法即可

                try {
                            Thread.sleep(2);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            e.printStackTrace();
                        }
    public static void main(String[] args) {
    
    
            Thread t1 = new Thread(() -> {
                for (int i = 0;i < 200;i ++){
                    if(!Thread.currentThread().isInterrupted()){
                        System.out.println("线程执行" + i + "| t1的中断标识为" + Thread.currentThread().isInterrupted());
                        try {
                            Thread.sleep(2);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            e.printStackTrace();
                        }
                    }else{
                        System.out.println("线程结束" + "| t1的中断标识为" + Thread.currentThread().isInterrupted());
                        break;
                    }
    
                }
            });
    
            Thread t2 = new Thread(() -> {
                System.out.println("t1的中断标识------" + t1.isInterrupted());
                try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
                t1.interrupt();
                System.out.println("t1的中断标识------" + t1.isInterrupted());
                try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
            });
            t1.start();
            t2.start();
        }

    执行结果,发现线程结束了

    线程执行0| t1的中断标识为false
    t1的中断标识------false
    线程执行1| t1的中断标识为false
    线程执行2| t1的中断标识为false
    线程执行3| t1的中断标识为false
    t1的中断标识------true
    线程结束| t1的中断标识为true
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at com.ruoyi.weixin.user.MyTest.IntrrupterTest.IntrrupterTest05.lambda$main$0(IntrrupterTest05.java:15)
        at java.lang.Thread.run(Thread.java:748)
    
    Process finished with exit code 0

    4.5 static interrupted()示例

        public static void main(String[] args) throws InterruptedException
        {
            System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
            System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
            System.out.println("111111");
            Thread.currentThread().interrupt();
            System.out.println("222222");
            System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
            System.out.println(Thread.currentThread().getName()+"---"+Thread.interrupted());
        }

    执行结果

      最开始两次调用Thread.interrupted(),发现都是默认false

      再调用了interrupt()被设为true

      第三次调用Thread.interrupted(),返回为true,且此时它把中断标识修改为false了

      所以,第四次调用Thread.interrupted(),返回为false

    main---false
    main---false
    111111
    222222
    main---true
    main---false

    5 小结

      中断只是一种协同机制,修改中断标识位仅此而已,不是立刻stop打断

    5.1 interrupt()方法

     当对一个线程,调用 interrupt() 时:
     
    ①  如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。
    被设置中断标志的线程将继续正常运行,不受影响。所以, interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。
     
    ②  如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,interrupt()设置的的true中断标识会被清除,变为false。线程也会退出被阻塞状态,并抛出一个InterruptedException异常,继续执行
     
     5.2 isInterrupted()

      获取线程的中断标识

    5.3 static interrupted()

       Thread.interrupted();  判断线程是否被中断,并清除当前中断状态,这个方法做了两件事:

        1 返回当前线程的中断状态

             2 将当前线程的中断状态设为false

  • 相关阅读:
    laydate 时间框弹窗点击弹出后立马消失的问题解决
    万字长文:ELK(V7)部署与架构分析
    人声消除的原理算法源码及方案实现
    主动降噪技术(ANC)的前生今世–行业分析
    主动降噪技术(ANC)的前生今世--原理仿真
    主动降噪技术(ANC)的前生今世--概念历史
    音频人生
    解决 Flask-sqlalchemy 中文乱码
    使用 key 登录时分开记录操作历史记录
    OpenSSH 使用技巧
  • 原文地址:https://www.cnblogs.com/jthr/p/16059132.html
Copyright © 2020-2023  润新知