【问题标题】:Returning from java method before all threads are done在所有线程完成之前从 java 方法返回
【发布时间】:2019-04-01 21:29:18
【问题描述】:

是否可以在所有线程完成之前从启动线程的 java 方法返回?

这是我的代码:

import java.util.concurrent.*;

public class ExecutorSample {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            service.execute(() -> {
                while (true) {
                }
            });
        }
        return;
    }
}

由于某种我不明白的原因,这不会返回。为什么工作线程卡住会影响主线程的返回?

【问题讨论】:

  • 你怎么知道方法没有返回?
  • @khelwood 我测试过,它卡在 main 上。
  • @ScaryWombat shutdownNow 也不起作用,因为它只是最好的尝试,实际上并没有关闭工作线程
  • @Jessica 你必须向我们展示你的测试结果,这可能是为什么有人不赞成你。此外,您应该在代码示例中显示测试。
  • 将代码放在另一个方法中,从main调用它,在另一个方法返回后在main中打印一些东西来测试其他方法是否返回。

标签: java multithreading thread-safety threadpool


【解决方案1】:

您的main 方法正在返回,但问题是您的JVM 没有退出。您可以通过将您的 main 方法重命名为其他名称来测试这一点,例如 doMain(),然后将 main 写为:

public static void main(String[] args) {
    doMain();
    System.out.printf("here");
}

你会看到你确实得到了输出,但程序并没有结束。

发生的事情是Executors.newCachedThreadPool 使用default thread factory,它创建了非守护线程。当您的main 方法返回时,JVM 将等待所有非守护线程完成(这就是它们与守护线程的区别——JVM 不会等待这些线程)。由于你所有的 Runnables 永远运行,非守护线程永远不会结束,JVM 永远不会退出。

你能做什么?一些选项:

  • 使用重载newCachedThreadPool(ThreadFactory),提供创建守护线程的ThreadFactory
  • 在您的 ExecutorService 上使用 shutdownNow()。这将在每个正在运行的线程上发送一个中断。您仍然需要在每个线程上检查它,方法是调用抛出 InterruptedException 的方法或显式调用 Thread.currentThread().isInterrupted()

对于shutdownNow 方法,请注意仅中断一个线程不足以停止它——在该线程上运行的代码必须通过检查其中断状态(使用一个这两种方法中的一种)并适当地退出。例如,您可以将while(true) 替换为while (!Thread.currentThread().isInterrupted())

【讨论】:

  • @yshavit 从您的回答看来,提供创建守护线程的线程工厂似乎是更好的方法。这种方法有什么缺点吗?
  • @Jessica:守护线程的缺点是,如果最后一个非守护线程退出,它们就会消失,没有机会进行清理。不要将守护线程用于您关心以受控方式完成的任何事情。
  • @NathanHughes Cool 有没有 Java 原生方式来构建这个工厂?我尝试了可以​​工作的番石榴 ThreadFactoryBuilder,但原生 java 方式会更好
  • 很高兴为您提供帮助,杰西卡!我不知道创建自定义线程工厂比番石榴更好的方法,或者只是编写自己的。创建 Thread 并不难,希望 javadocs 是不言自明的。 (另外,感谢@NathanHughes 修正了这个错字!)
猜你喜欢
  • 2015-09-21
  • 1970-01-01
  • 1970-01-01
  • 2016-02-27
  • 2017-06-07
  • 2019-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多