在Java中停止/结束所有线程

3
我正在编写一个程序,从我的主函数中调用多个线程。有一个for循环在循环中启动线程。
我想实现一个功能,即如果一个线程发生异常,则应停止所有当前运行/提交的线程或处于等待状态的线程。并且从循环中不再提交更多的线程。
附言:我正在维护一个Map,其中记录了所有线程 Map ,并且我没有使用executor service。
如何在任何一个线程出现异常后杀死或停止所有线程,并防止进一步提交线程。

你的问题确切是什么? - shmosel
3
请参考 https://dev59.com/dnRB5IYBdhLWcg3wSVcI?rq=1,您可能应该使用一些ExecutorService。 - user180100
@sh 如果任何线程发生异常,如何停止所有线程(当前正在运行或等待提交的线程)。 - chumak
1
@RC是正确的。请参阅https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html。您将在那里找到一些关闭方法。 - Shubham Chaurasia
4个回答

2
请注意,Java中没有“内置”功能来停止线程 - 一些方法确实存在,但全部已弃用,因为如果运行代码不合作,可能会引起问题。因此,您的代码必须实现某种基于某个标志退出run()方法的方法,并且这必须从线程外部设置。如果您的线程经常使用wait(),则调用interrupt()可能会有所帮助。

2

在Java中,你不能强制停止一个线程。

是的,有像 Thread.stop() 等方法,但它们已经被废弃多年了 ,有充分的理由

为什么 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. 当需要结束线程时,在主方法中通过调用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。请勿使用Thread.stop()来终止线程。

0

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

关于终止所有正在运行的线程,请参考此线程


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

目前所有线程都有thread.join。但如果线程1发生异常,线程2仍将执行。 我希望如果线程1发生异常,则所有具有thread1.join的线程甚至不等待线程1的线程也不应该执行。当前正在运行的线程也应该停止。 - chumak
调用 thread.join() 不会保证立即终止线程,而是会等待其他线程完成并返回。 - Kiran Kumar
Thread.stop() 已经被废弃至少20年。 - user207421
2
yield() 不会使线程停止,它只是表示“我认为现在是将一些 CPU 时间分配给其他任务的好时机”。 - piet.t
“Recent versions of Java” 包括自1997年5月以来的每个版本。那么,“recent”是指多近? - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接