如何杀死Java线程

2023/06/07

1. 概述

在这篇简短的文章中,我们将介绍如何在Java中终止一个线程,这并不是那么简单,因为Thread.stop()方法已被弃用

正如Oracle的此更新中所述,stop()可能会导致被监视的对象损坏。

2. 使用标志

让我们从一个创建和启动线程的类开始,这个任务不会自行结束,因此我们需要某种方法来停止该线程。

我们将为此使用一个原子标志:

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

    public ControlSubThread(int sleepInterval) {
        interval = sleepInterval;
    }

    public void start() {
        worker = new Thread(this);
        worker.start();
    }

    public void stop() {
        running.set(false);
    }

    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");
            }
            // do something here
        }
    }
}

在while循环中我们使用的不是常量true,而是一个AtomicBoolean,现在我们可以通过将其设置为true/false来启动/停止执行。

正如我们在原子变量简介中所解释的,使用AtomicBoolean可以防止在不同线程中设置和检查变量时发生冲突。

3. 中断线程

如果sleep()设置为长时间间隔,或者如果我们等待一个可能永远不会释放的锁,会发生什么?

我们会面临着长期阻塞或永远无法完全终止的风险

我们可以为这种情况创建一个interrupt(),让我们在类中添加一些方法和一个新标志变量:

public class ControlSubThread implements Runnable {
    private Thread worker;
    private AtomicBoolean running = new AtomicBoolean(false);
    private int interval;
    // ...

    public void interrupt() {
        running.set(false);
        worker.interrupt();
    }

    boolean isRunning() {
        return running.get();
    }

    boolean isStopped() {
        return stopped.get();
    }

    public void run() {
        running.set(true);
        stopped.set(false);
        while (running.get()) {
            try {
                Thread.sleep(interval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("Thread was interrupted, Failed to complete operation");
            }
            // do something
        }
        stopped.set(true);
    }
}

我们添加了一个interrupt()方法,该方法将running标志设置为false,并调用worker线程的interrupt()方法。

如果调用此方法时线程处于睡眠状态,sleep()将退出并抛出InterruptedException,就像任何其他阻塞调用一样。

这会将线程返回到while循环,并且因为上一步设置running为false,所以它将退出。

4. 总结

在这个快速教程中,我们研究了如何使用原子变量,结合对interrupt()的调用,优雅地关闭线程,这绝对比调用已弃用的stop()方法并冒着永远锁定和内存损坏的风险要好。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章