为何建议不使用 stop 方法中止线程?

保存好你作过的全部源文件——那是你最好的积累之一。安全

线程启动完毕后,在运行时可能须要终止,Java提供的终止方法只有一个stop,可是我不建议使用这个方法,由于它有如下三个问题:多线程

(1)stop方法是过期的从Java编码规则来讲,已通过时的方法不建议采用。ide

(2)stop方法会致使代码逻辑不完整stop方法是一种“恶意”的中断,一旦执行stop方法,即终止当前正在运行的线程,无论线程逻辑是否完整,这是很是危险的。看以下的代码:编码

public static void main(String[] args) throws Exception {
    // 子线程
    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                // 子线程休眠一秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // 异常处理
            }
        }
    };
    // 启动线程
    thread.start();
    // 主线程休眠一秒
    Thread.sleep(1000);
    // 子线程中止
    thread.stop();
}

这段代码的逻辑是这样的:子线程是一个匿名内部类,它的run方法在执行时会休眠1秒钟,而后再执行后续的逻辑,而主线程则是休眠0.1秒后终止子线程的运行,也就是说,JVM在执行thread.stop()时,子线程还在执行sleep(1000),此时stop方法会清除栈内信息,结束该线程,这也就致使了run方法的逻辑不完整,输出语句println表明的是一段逻辑,可能很是重要,好比子线程的主逻辑、资源回收、情景初始化等,可是由于stop线程了,这些就都再也不执行,因而就产生了业务逻辑不完整的状况。线程

这是极度危险的,由于咱们不知道子线程会在何时被终止,stop连基本的逻辑完整性都没法保证。并且此种操做也是很是隐蔽的,子线程执行到何处会被关闭很难定位,这为之后的维护带来了不少麻烦。code

(3)stop方法会破坏原子逻辑多线程为了解决共享资源抢占的问题,使用了锁概念,避免资源不一样步,可是正所以缘由,stop方法却会带来更大的麻烦:它会丢弃全部的锁,致使原子逻辑受损。例若有这样一段程序:接口

class MultiThread implements Runnable {
    int a = 0;

    @Override
    public void run() {
        // 同步代码块,保证原子操做
        synchronized ("") {
            a++; // 自增
            try {
                // 线程休眠0.1秒
                Thread.sleep(100);
            } catah(InterruptedException e) {
                e.printStackTrace();
            }
            a--; // 自减
            String tn = Thread.currentThread().getName();
            System.out.println(tn + ":a=" + a);
        }
    }
}

MultiThread实现了Runnable接口,具有多线程能力,其中run方法中加上了synchronized代码块,表示内部是原子逻辑,它会先自增而后再自减小,按照synchronized同步代码块的规则来处理,此时不管启动多少个线程,打印出来的结果都应该是a=0,可是若是有一个正在执行的线程被stop,就会破坏这种原子逻辑,代码以下:资源

public static void main(String[] args) {
    MultiThread thread = new MultiThread();
    Thread thread1 = new Thread(thread);
    // 启动thread1线程
    thread1.start();
    for (int i = 0; i < 5; i++) {
        new Thread(thread).start();
    }
    // 中止thread1线程
    thread1.stop();
}

首先要说明的是全部线程共享了一个MultiThread的实例变量t,其次因为在run方法中加入了同步代码块,因此只能有一个线程进入到synchronized块中。此段代码的执行顺序以下:get

1)线程t1启动,并执行run方法,因为没有其余线程持同步代码块的锁,因此t1线程执行自加后执行到sleep方法即开始休眠,此时a=1。同步

2)JVM又启动了5个线程,也同时运行run方法,因为synchronized关键字的阻塞做用,这5个线程不能执行自增和自减操做,等待t1线程锁释放。

3)主线程执行了t1.stop方法,终止了t1线程,注意,因为a变量是全部线程共享的,因此其余5个线程得到的a变量也是1。

4)其余5个线程依次得到CPU执行机会,打印出a值。

分析了这么多,相信读者也明白了输出的结果,结果以下:

Thread-5:a=1
Thread-4:a=1
Thread-3:a=1
Thread-2:a=1
Thread-1:a=1

本来指望synchronized同步代码块中的逻辑都是原子逻辑,不受外界线程的干扰,可是结果却出现原子逻辑被破坏的状况,这也是stop方法被废弃的一个重要缘由:破坏了原子逻辑。

既然终止一个线程不能使用stop方法,那怎样才能终止一个正在运行的线程呢?答案也很简单,使用自定义的标志位决定线程的执行状况,代码以下:

class SafeStopThread extends Thread {
    // 此变量必须加上volatile
    private volatile boolean stop = false;

    @Override
    public void run() {
        // 判断线程体是否运行
        while (stop) {
            // Do Something
        }
    }
    // 线程终止
    public void terminate() {
        stop = true;
    }
}

这是很简单的办法,在线程体中判断是否须要中止运行,便可保证线程体的逻辑完整性,并且也不会破坏原子逻辑。可能有读者对Java API比较熟悉,因而提出疑问:Thread不是还提供了interrupt中断线程的方法吗?这个方法可不是过期方法,那可使用吗?它能够终止一个线程吗?

很是好的问题,interrupt,名字看上去很像是终止一个线程的方法,可是我能够很明确地告诉你,它不是,它不能终止一个正在执行着的线程,它只是修改中断标志而已,例以下面一段代码:

public static void main(String[] args) {
    Thread thread = new Thread() {
        public void run() {
            // 线程一直运行
            while (true) {
                System.out.println("Running...");
            }
        }
    };
    // 启动thread线程
    thread.start();
    // 中断thread线程
    thread.interrupt();
}

执行这段代码,你会发现一直有Running在输出,永远不会中止,彷佛执行了interrupt没有任何变化,那是由于interrupt方法不能终止一个线程状态,它只会改变中断标志位(若是在t1.interrupt()先后输出t1.isInterrupted()则会发现分别输出了false和true),若是须要终止该线程,还须要自行进行判断,例如咱们可使用interrupt编写出更加简洁、安全的终止线程代码:

class SafeStopThread extends Thread {
    @Override
    public void run() {
        // 判断线程体是否运行
        while (!isInterrupted()) {
            // Do Something
        }
    }
}

总之,若是指望终止一个正在运行的线程,则不能使用已通过时的stop方法,须要自行编码实现,如此便可保证原子逻辑不被破坏,代码逻辑不会出现异常。固然,若是咱们使用的是线程池(好比ThreadPoolExecutor类),那么能够经过shutdown方法逐步关闭池中的线程,它采用的是比较温和、安全的关闭线程方法,彻底不会产生相似stop方法的弊端。

相关文章
相关标签/搜索