java 如何正确的停止线程

  • Post author:
  • Post category:java




java 如何正确的停止线程



错误方式一:使用stop()

stop()方法在jdk中被标记为@deprecated,并解释此方法本质上是不安全的,因为当调用某个线程的stop()方法时,此线程会被强行停止,不能将该线程的run()方法中的逻辑执行完全,可能会造成线程中的数据被破坏。

java API文档



代码示例:

/**
 * @author Ice, You're very best
 * @date 2018/10/24 14:47
 * @desc 停止线程的错误方法stop()
 */
public class WrongWayToStop implements Runnable{

    public static void main(String[] args) {
        Thread thread = new Thread(new WrongWayToStop());

        System.out.println("线程启动");
        thread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("中断线程");
        thread.stop();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程结束");
    }

    @Override
    public void run() {
        int count = 0;
        while (true){
            System.out.println("线程在运行中" + (++count));//输出当前循环执行了多少次
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) {
                System.out.println("线程正确结束,执行收尾逻辑,如清理工作,关闭流或连接等");
                return;
            }
        }
    }
}

以上代码的输出结果如下:

线程启动
线程在运行中1
线程在运行中2
线程在运行中3
中断线程
线程结束

由上可见,thread线程的run()方法中,本该执行10次的循环体在执行到第三次就因为stop()方法而终止了线程,后面循环结束的收尾逻辑如关闭流关闭连接等都没有执行,因此,stop()中断线程是一种错误的方法。



正确方式:使用退出标记

如上图java doc所述

Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running.

使用stop()方法的地方应该通过简单修改一个变量来标识目标线程为“需要停止运行”

因此,将以上代码略作修改即可正确停止该线程

/**
 * @author Ice, You're very best
 * @date 2018/10/24 14:47
 * @desc 停止线程的正确方法
 */
public class WrongWayToStop implements Runnable{

    volatile boolean keepRunning = true;

    public static void main(String[] args) {
        WrongWayToStop wrongWayToStop = new WrongWayToStop();
        Thread thread = new Thread(wrongWayToStop);

        System.out.println("线程启动");
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("中断线程");
        wrongWayToStop.keepRunning = false;
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程结束");
    }

    @Override
    public void run() {
        while (keepRunning){
            for (int i = 0; i < 10; i++) {
                System.out.println("线程在运行中" + i);//输出当前循环执行了多少次
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("线程正确结束,执行收尾逻辑,如清理工作,关闭流或连接等");
    }
}

输出结果如下:

线程启动
线程在运行中0
线程在运行中1
线程在运行中2
线程在运行中3
线程在运行中4
中断线程
线程在运行中5
线程在运行中6
线程在运行中7
线程在运行中8
线程在运行中9
线程结束
线程正确结束,执行收尾逻辑,如清理工作,关闭流或连接等

如此,线程执行完完整的逻辑后安全的结束。



另一种错误方式:interrupt()

网上广为流传的另一种停止线程的方式,使用Thread类的interrupt()方法中断线程,我们来试试这种方式

/**
 * @author Ice, You're very best
 * @date 2018/10/24 14:47
 * @desc 停止线程的错误方法interrupt()
 */
public class WrongWayToStop extends Thread{

    public static void main(String[] args) {
        WrongWayToStop wrongWayToStop = new WrongWayToStop();

        System.out.println("线程启动");
        wrongWayToStop.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("中断线程");
        wrongWayToStop.interrupt();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程结束");
    }

    @Override
    public void run() {
        while (!this.isInterrupted()){
            for (int i = 0; i < 10; i++) {
                System.out.println("线程在运行中" + i);//输出当前循环执行了多少次
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("线程正确结束,执行收尾逻辑,如清理工作,关闭流或连接等");
    }
}

输出结果如下:

线程启动
线程在运行中0
线程在运行中1
线程在运行中2
线程在运行中3
线程在运行中4
java.lang.InterruptedException: sleep interrupted
中断线程
	at java.lang.Thread.sleep(Native Method)
线程在运行中5
	at stopthread.WrongWayToStop.run(WrongWayToStop.java:37)
线程在运行中6
线程在运行中7
线程在运行中8
线程在运行中9
线程结束
线程在运行中0
线程在运行中1
线程在运行中2
线程在运行中3
线程在运行中4
线程在运行中5
.//由于线程未能正确停止,此处强行停止了进程任务
.
.

我们使用interrupt()方法标记该线程状态为中断,在线程的run()方法中使用isInterrupted()判断线程状态来停止线程,表面上并没有什么不妥,但是输出结果却在输出“线程结束”后仍然继续输出“线程在运行中”,也就是说线程其实并没有结束,而且在输出结果中还抛出了一个异常

java.lang.InterruptedException: sleep interrupted

,由此可见目标线程没有正确停止很有可能是这个异常造成的。再次查阅intterupt()方法的文档描述:

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

如果当前线程由于wait()……join()……sleep()……等方法的调用而被阻塞,它的intterupt状态会被清除并且会接收一个InterruptedException。

至此,原因很清晰了,我们在目标线程的run()方法中调用了sleep(),所以在主线程中调用目标线程的interrupt()方法时,会抛出InterruptedException,目标线程的interrupte状态也被清除了,因此while(this.isInterrupted()){}代码块会一直运行下去,永不停止。所以使用interrupt()方法来中断线程也不是一个好办法,因为我们不能保证永远不使用wait(),join(),sleep()等方法。

以上就是关于java正确停止一个线程的基本知识,只代表个人观点,如有不对,请留言指正!



版权声明:本文为BING835687152原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。