8.优雅地停止线程


 

 

优雅地停止线程

 导言

如何让正在运行的线程优雅的停下来,这个问题一直是面试必考题。下面将介绍一种让线程优雅的停下来的方法,这就是位于thread类里面的interrupt方法,

 

它的作用就是中段线程。

接下来我们将从两个方面演示该方法。

第一个方面就是停止正在运行的线程。

第二个方面就是停止休眠中的线程。

 

停止正在运行的线程

首先来看第一个方面,我们先定义一个任务,任务的内容,就是无限输出正在运行这句话。

package com.chenjie.executor.day08;

/**
 * 自定义task
 */
public class Task implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("正在执行");
        }
    }
}

接下来我们将任务创建出来,然后创建线程并将任务传递给线程,接着启动线程,为了让中断效果更明显,在中段线程前,就用sleep方法使主线程休眠一秒钟,最后就用interrupt方法中断线程。

package com.chenjie.executor.day08;

public class Main1 {
    public static void main(String[] args) {
       Task task=new Task();
        Thread thread = new Thread(task);
        thread.start();
        try {
            thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();

    }
}

从运行结果来看,好像出了点问题,线程没有停下来,程序也没有结束,这是怎么回事?

 

 

原因就在于 interrupt方法仅仅只是将线程标记为中断状态,

他没有实际去停止这个线程,如果想要线程停下来,则需要我们手动去判断线程是否被中断,然后对此作出反应

判断线程是否被中断,有两个方法,分别是 isinterrupted和interrupt的。

Is interrupt的是一个非静态方法,它的作用是判断线程是否被中断。

Interrupt的是一个静态方法,它可以直接被thread的类名调用,作用也是判断线程是否被中断,并且它可以清除中断标记,这也是它和interrupt的方法的区别。 

下面来看看这两个方法分别如何如何使用。首先是isinterrupt的。他返回一个布尔类型,线程被中段返回true,否则返回false。

改写之前的任务,首先调用currentthread方法获取当前正在执行任务的线程,然后调用该线程的isinterrupt,判断线程是否被中断。当线程被中断时,结束循环,此时线程就停下来了。

package com.chenjie.executor.day08;

/**
 * 自定义task
 */
public class Task implements Runnable {
    @Override
    public void run() {
        while (true) {
            Thread thread = Thread.currentThread();
            if(thread.isInterrupted()){
                break;
            };
            System.out.println("正在执行");
        }
    }
}

下面来看一下运行结果。从运行结果来看,程序经过一秒钟后运行结束,说明线程的确被中断了。

下面再来看看interrupt的方法,它返回的也是一个Boolean类型,线程被中断返回true,否则返回false。 

 

改写之前的任务,这里直接使用所谓的类名调用interrupt的方法,判断线程是否被中断,当线程被中断时结束循环。

package com.chenjie.executor.day08;

/**
 * 自定义task
 */
public class Task1 implements Runnable {
    @Override
    public void run() {
        while (true) {
            if(Thread.interrupted()){
                break;
            };
            System.out.println("正在执行");
        }
    }
}

下面来看一下运行结果。从运行结果来看,程序也是经过一秒钟后结束,说明线程也的确被中断了。

package com.chenjie.executor.day08;

public class Main1 {
    public static void main(String[] args) {
//       Task task=new Task();
//        Thread thread = new Thread(task);
//        thread.start();
//        try {
//            thread.sleep(1000L);
//        } catch (InterruptedException e) {
//            e.printStackTrace();a
//        }
//        thread.interrupt();

               Task1 task=new Task1();
        Thread thread = new Thread(task);
        thread.start();
        try {
            thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();

    }
}

 

线程中断

接下来我们来看看线程中断的标记是怎样的。首先来看isInterrupted的方法的输出结果。从结果来看,线程一开始它没有被中断,输出的结果是false,一秒钟后线程被中断,输出的结果变为了true。

package com.chenjie.executor.day08;

/**
 * 自定义task
 */
public class Task2 implements Runnable {
    @Override
    public void run() {
        while (true) {
            Thread thread = Thread.currentThread();
            System.out.println(thread.isInterrupted());
        }
    }
}
false
false
false
true
true
true

 

我们再来看看interrupted的方法,从结果来看,它的结果和之前的结果有点不同,线程一开始没有被中断,输出的结果为false,一秒钟后线程被中断,结果变true了。然后线程中段标记被清除,输出的结果又变为了false。 

false
false
false
true
true
true
false
false
false

 

停止休眠中的线程

好的,第一个方面,演示完毕。我们再来看看第二种方面,停止休眠中的线程,还是自定义一个任务,然后调用sleep方法,使当前线程休眠10秒钟,使用try catch捕获thread方法抛出的异常。

package com.chenjie.executor.day08;

public class Main1 {
    public static void main(String[] args) {
//       Task2 task=new Task2();
//        Thread thread = new Thread(task);
//        thread.start();
//        try {
//            thread.sleep(1000L);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        thread.interrupt();

//        Task3 task = new Task3();
//        Thread thread = new Thread(task);
//        thread.start();
//        try {
//            thread.sleep(1000L);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        thread.interrupt();
        Task4 task = new Task4();
        Thread thread = new Thread(task);
        thread.start();
        try {
            thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
    }
}
package com.chenjie.executor.day08;

/**
 * 自定义task
 */
public class Task4 implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(10000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

下面来看看运行结果怎么样。从运行结果来看,程序发生了异常,该异常是中断休眠中的线程引发的,叫做中段线程异常。

 

 

 总结

最后我们来总结一下本节内容,本节介绍了thread里面三个方法,第一个是interrupt方法,它是一个非静态方法,作用是中断线程。

第二个是isinterrupted的方法,它也是一个非静态方法,作用是判断线程是否被中断。 

第三个是interrupted方法,它是一个静态方法,直接通过所谓的类名调用,作业是判断线程是否被中断,并清除中断标记,在实际开发中偶尔也会用到它们。 

 

posted @ 2022-04-26 23:04  小陈子博客  阅读(223)  评论(0编辑  收藏  举报