Java多线程开发中如何优雅的停止线程

Java多线程开发中如何优雅的停止线程


通常我们在执行一个线程任务的时候,如果想终止执行,会第一时间想到调用Thread.stop();方法。
不过该方法带来的危险性极大,在JDK中该方法已经被明确弃用。原因是因为它天生不安全,停止一个线程导致它将解锁锁定的所有的监视器,如果任何一个线程预先通过这些监视器保护是一个不一致的状态,其他线程现在查看这些对象是不一致的状态,像这些对象可以说是破坏了。 当线程操作一个坏的对象会得到一个不正确的结果。这种行为可能很微妙,很难察觉,也可能很明显。不像其他未检查异常,ThreadDeath异常将会静默杀死线程。因此,这个用户没有任何警告,他的程序将会被破坏

那有没有新的解决办法呢?

停止线程的行为大多数用法应该由代码修改,该代码只是修改某个变量以指示目标线程应该停止运行。 目标线程应该定期检查此变量,并且如果变量指示它将停止运行,则以有序的方式从其run方法返回。 为了确保快速通信停止请求,变量必须是可见性volatile的(或者必须同步对变量的访问)。

举例子:

// 使用基于可见性变量 循环检测,当信号收到,run方法退出不再执行,从而停止线程
public class InterruptedThread1 implements Runnable {

    private volatile Thread blinker;
    private AtomicInteger atomicInteger = new AtomicInteger(0);
    private void stop() {
        blinker = null;
    }

    @Override
    public void run() {
        Thread thisThread = Thread.currentThread();
        while (blinker == thisThread) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("线程发生中断异常...");
            }
            System.out.println("线程运行中,正在处理一些事情..." + atomicInteger.incrementAndGet());
            if (atomicInteger.get() == 5) {
                this.stop();
            }
        }
        System.out.println("线程任务执行完毕,释放返回 停止");
    }

    public static void main(String[] args) {
        InterruptedThread1 interruptedThread = new InterruptedThread1();
        Thread thread = new Thread(interruptedThread);
        interruptedThread.blinker = thread;
        thread.start();
    }

线程中断

另外的一种基于线程中断信号机制的办法:Thread.interrupt方法可以使用上面显示的相同的“基于状态”的信令机制,但是状态更改(blinker = null,在前面的示例中)之后可以调用Thread.interrupt来中断等待:

每个线程都有一个与之关联的布尔属性,表示其中断状态。中断状态最初为假;当一个线程被某个其他线程通过调用中断时, Thread.interrupt()会发生以下两种情况之一。如果该线程正在执行低级别的中断阻塞方法等 Thread.sleep(),Thread.join()或 Object.wait(),它放开并抛出 InterruptedException。除此以外,interrupt()仅设置线程的中断状态。在中断线程中运行的代码可以稍后轮询中断状态以查看是否已请求停止它正在执行的操作;可以读取中断状态,Thread.isInterrupted()并且可以使用名称不佳的单个操作读取和清除 中断状态Thread.interrupted()。

    中断是一种合作机制。当一个线程中断另一个线程时,被中断的线程不一定会立即停止它正在做的事情。相反,中断是一种礼貌地要求另一个线程在方便的时候停止它正在做什么的方式。一些方法,例如Thread.sleep(),认真对待这个请求,但不要求方法注意中断。不阻塞但仍可能需要很长时间才能执行的方法可以通过轮询中断状态来尊重中断请求,并在中断时提前返回。您可以自由地忽略中断请求,但这样做可能会影响响应速度。
    中断的合作性质的一个好处是它为安全地构建可取消的活动提供了更大的灵活性。我们很少想立即停止活动;如果活动在更新期间被取消,程序数据结构可能会处于不一致状态。中断允许可取消活动清理正在进行的任何工作,恢复不变量,通知其他活动取消,然后终止。

举例子

public class InterruptedThread2 implements Runnable {
    private Thread worker;
    private final AtomicBoolean running = new AtomicBoolean(false);

    private final AtomicInteger atomicInteger = new AtomicInteger();


    private int interval;

    public InterruptedThread2(int sleepInterval) {
        interval = sleepInterval;
    }
    public void start() {
        worker = new Thread(this);
        worker.start();
    }
    public void stop() {
       // running.set(false);
        Thread.currentThread().interrupt();
    }
    public void run() {
        running.set(true);
        while (running.get()) {
            try {
                Thread.sleep(interval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println(
                        "Thread was interrupted, Failed to complete operation");
                return;
            }
            // do something here
            System.out.println("线程运行中,正在处理一些事情..." + atomicInteger.incrementAndGet());
            if (atomicInteger.get() == 3) {
                this.stop();
            }
        }
        System.out.println("线程任务执行完毕,释放返回 停止");

    }

    public static void main(String[] args) {
        InterruptedThread2 interruptedThread2 = new InterruptedThread2(3000);
        interruptedThread2.start();
        interruptedThread2.stop();
        Thread.currentThread().stop();
    }
}

总结:通过使用可见性变量或者线程中断信号传递信号改变线程状态去完美替换调用弃用的thread.stop()方法

 Git使用教程常用命令总结
小米手机刷机经验 
上一篇:Git使用教程常用命令总结
下一篇:小米手机刷机经验
评论

如果我的文章对你有帮助,或许可以打赏一下呀!

支付宝
微信
QQ