【问题标题】:Stopping/Killing all threads in Java停止/杀死Java中的所有线程
【发布时间】:2017-05-06 12:27:45
【问题描述】:

我正在编写一个程序,我从我的主函数调用多个线程。有一个 For 循环,它在循环中启动线程。 我想实现一个功能,如果一个线程中发生一些异常,那么它应该停止所有当前正在运行/提交的线程,或者处于等待状态的线程。并且不应再从循环中提交更多线程。

附:我正在维护一个记录所有线程Map <threadName, Thread> 的地图 而且我没有使用执行器服务。

在任何一个线程发生异常后,如何杀死或停止所有线程并防止提交更多线程。

【问题讨论】:

标签: java multithreading


【解决方案1】:

您不能在 Java 中强制停止线程。

是的,有像 Thread.stop() 和相关的方法,但它们已被弃用多年 for good reason

为什么不推荐使用Thread.stop
因为它本质上是不安全的。停止线程会导致它解锁所有已锁定的监视器。 (监视器在ThreadDeath 异常向上传播时解锁。)如果以前受这些监视器保护的任何对象处于不一致状态,其他线程现在可能会以不一致的状态查看这些对象。据说这些物体已损坏。当线程对损坏的对象进行操作时,可能会导致任意行为。这种行为可能很微妙且难以检测,也可能很明显。与其他未经检查的异常不同,ThreadDeath 以静默方式杀死线程;因此,用户没有警告他的程序可能已损坏。损坏可以在实际损坏发生后的任何时间出现,甚至在未来几小时或几天内。

由于上述原因,您不应使用这些方法,也不应依赖它们工作(许多具有大量线程方法的 API 会很乐意忽略对 stop()interrupt() 的任何调用)。

一旦我们解决了这个问题,您仍然可以以一种优雅的方式为您的线程实现逻辑,以便在您要求它们时尽快终止。

你需要做两件事:

1.- 在 run() 方法中检查 Thread.interrupted()。像这样的:

@Override
public synchronized void run() {
    while (yourFinishCondition && !Thread.interrupted()) {
        // do stuff until you finish, or until the thread is interrupted from the outside
    }
}

2.- 在您的 main 方法中的每个线程上调用 interrupt(),以便在需要时向它们发出终止信号,如下所示:

Thread.UncaughtExceptionHandler h = (thread, exception) -> {
    thread0.interrupt();
    thread1.interrupt();
    thread2.interrupt();
};

一点 PoC:

public class Main {

    static class MyThread extends Thread {
        public MyThread(String s) {
            super(s);
        }
        @Override
        public synchronized void run() {
            while(!Thread.interrupted()) {
                if (new Random().nextInt(1000000) == 7) {
                    throw new RuntimeException(Thread.currentThread().getName()+" oops!");
                }
            }
            System.out.println(Thread.currentThread().getName()+" interrupted");
        }
    }

    public static void main(String[] args) {
        final MyThread thread0 = new MyThread("thread0");
        final MyThread thread1 = new MyThread("thread1");
        final MyThread thread2 = new MyThread("thread2");

        Thread.UncaughtExceptionHandler h = (thread, exception) -> {
            System.out.println(exception.getMessage());
            thread0.interrupt();
            thread1.interrupt();
            thread2.interrupt();
        };
        thread0.setUncaughtExceptionHandler(h);
        thread1.setUncaughtExceptionHandler(h);
        thread2.setUncaughtExceptionHandler(h);

        thread0.start();
        thread1.start();
        thread2.start();
    }
}

输出:

thread2 oops!
thread1 interrupted
thread0 interrupted

延伸阅读:https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop()+to+terminate+threads

【讨论】:

    【解决方案2】:

    请注意,在 java 中没有“内置”功能来停止线程 - 有些方法确实存在,但都已弃用,因为如果正在运行的代码不合作,它们可能会导致麻烦。所以你的代码必须实现一些方法来基于一些标志退出run()-method,这必须从线程外部设置。如果您的线程经常使用wait(),那么调用interrupt() 可能会派上用场。

    【讨论】:

      【解决方案3】:

      你可以编写代码来杀死finally块或catch块中所有正在运行的线程(可能不推荐)

      杀死所有正在运行的线程,refer this thread

      【讨论】:

        【解决方案4】:

        如果我的问题是正确的,您需要捕获异常并需要将列表保留/维护为共享对象,然后在其他线程上调用 thread.stop() 将解决问题对吗?但是stop方法在最近的java版本中已经被弃用了,所以可以使用thread.yield()让线程释放CPU等资源,但仍然不能保证线程立即终止。

        【讨论】:

        • 目前所有线程都有thread.join。但是如果线程 1 发生异常,线程 2 仍然会执行。我想如果线程 1 中发生异常,那么所有具有 thread1.join 的线程甚至不等待线程 1 的线程都不应该执行。并且当前正在运行的线程也应该停止
        • 调用thread.join()并不能保证它会立即终止线程,而是等待其他线程完成并返回。
        • Thread.stop() 已被弃用至少 20 年。
        • yield() 不会让线程停止,它只是说“我认为这是给其他任务一些 CPU 的好时机”。
        • “Java 的最新版本”包括至少自 1997 年 5 月以来的所有版本。“最近”有多近?
        猜你喜欢
        • 2014-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-30
        • 1970-01-01
        相关资源
        最近更新 更多