停止线程的正确姿势

停止线程的正确姿势

原文地址

Java线程状态和关闭线程的正确姿势

正文

线程的run()方法正常执行完毕之后线程就正常死亡进入TERMINATED状态了,那么如果我们有中途停止线程的需求,我们应该如何正确的结束一个线程呢?

使用interrupt()方法

在线程内部,其定义了一个变量来标识当前线程是否处于被打断状态,调用interrupt()方法则使这个状态变为true;换句话说,线程在阻塞状态的时候会检查标识状态,如果是true,则抛出InterruptedException,否则阻塞,所以不会打断非阻塞的线程,即对正在运行的线程此方法无效。我们采用这个方法加异常处理的方式来结束一个线程。

  public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                // 这里的return是必须的,原因后面说明
                return;
            }
            System.err.println("thread interrupt test...");
        });
        thread.start();
        thread.interrupt();
        System.out.println("main thread end...");
    }

在这里插入图片描述

这里关于线程中的打断标识变量(之后以interrupt称)需要说明的是,在特定的情况下其状态会被重置。

  1. 线程内部在catch了异常之后interrupt的状态会被重置为false。
  2. 线程调用了Thread.interrupted()方法之后,interrupt的状态会被重置为false。如果需要判断线程是否中断的话可以使用对象方法isInterrupted(),此方法不会重置。

所以在刚才的代码中需要加入return来结束线程,否则的话线程还是会继续往下执行,如下图:
在这里插入图片描述
使用isInterrupted()实现:

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        while (!Thread.currentThread().isInterrupted()) {
            int k = 0;
            while (k++ < 10) {
                System.out.println("do something..." + k);
            }
        }
    System.err.println("thread end...");
    });
    thread.start();
    Thread.sleep(1);
    // 主线程流程执行完了,需要停止线程
    thread.interrupt();
}

stop()方法——不正确的线程中断方法

在线程提供的方法中还有一个方法可以强制关闭线程——stop()。这个方法可以说是相当的霸道,给人一种“我不管,我就是要你现在立刻死亡(指线程)”的感觉,并且其还会释放线程所有的锁资源,这样可能会导致出现数据不一致从而出现线程不安全的情况,如下面例子。

public class Test {

        public static volatile boolean flag = false;
        public int state = 0;

        public static void main(String[] args) throws InterruptedException {
            Test test = new Test();
            Thread thread = new Thread(() -> {
                synchronized (test) {
                    try {
                        test.state = 1;
                        Thread.sleep(100);
                        if (flag) {
                            test.state = 2;
                        }
                        System.err.println("thread execute finished...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            thread.start();
            Thread.sleep(1);
            thread.stop();
            flag = true;
            System.out.println("state状态:" + test.state);
        }
}

在这段代码中,进入线程时默认将state赋为1,接着过一段时间后如果触发了特定条件则把state赋为2,但是在特定条件触发之前,线程就被终止掉了,这个特定条件虽然符合但却没办法执行,从而导致数据的不一致。
结果图:
在这里插入图片描述

所以,我们应该采用上面正确的方式而不是stop()来中止线程。此外,stop()方法若在线程start()之前执行,那么在线程启动的时候就会立即死亡。

发布了301 篇原创文章 · 获赞 435 · 访问量 71万+

猜你喜欢

转载自blog.csdn.net/qq_37960603/article/details/104319279