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