java并发编程:为什么不要用stop方法停止线程

Published on 2024-06-21 16:12 in 分类: 随笔 with 狂盗一枝梅
分类: 随笔

java并发编程:为什么不要用stop方法停止线程

首先先看一段代码:

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        StopThread thread = new StopThread();
        thread.start();
        Thread.sleep(1000L);
        thread.stop();
        while (thread.isAlive()) {
        }
        thread.print();
    }

    private static class StopThread extends Thread {
        private int x = 0;
        private int y = 0;
    
        @Override
        public void run() {
            synchronized (this) {
                ++x;
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ++y;
            }
        }

        public void print() {
            System.out.println("x=" + x + " y=" + y);
        }
    }
}

这段代码的本意是x和y要一起自增1,也就是x=1、y=1;然而这段代码输出如下

x=1 y=0

如果我们把主线程中的Thread.sleep(1000L);代码注释掉,再次运行代码,代码输出如下

x=1 y=1

这其实才是我们想要得到的结果。由于任性调用stop方法,导致y还还没有自增线程就挂掉了,没有异常,也破坏了我们的预期。如果这种问题出现在我们的程序中,会引发难以预料的异常。因此这种不安全的方式很早就被废弃掉了。

正确的做法是让业务决定是否停止线程,这样才能保持业务的处理和线程停止结果的一致性。正常关闭线程的demo如下

public class MyRunnableMain {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
        try {
            Thread.sleep(10L * 1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myRunnable.doStop();
    }
}


class MyRunnable implements Runnable {
    private boolean doStop = false;

    public synchronized void doStop() {
        this.doStop = true;
    }

    private synchronized boolean keepRunning() {
        return !this.doStop;
    }

    @Override
    public void run() {
        while (keepRunning()) {
            // keep doing what this thread should do.
            System.out.println("Running");
            try {
                Thread.sleep(3L * 1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果就是

Running
Running
Running
Running

这样关闭线程才优雅。


#并发编程