在所有线程完成之前从 java 方法返回
Posted
技术标签:
【中文标题】在所有线程完成之前从 java 方法返回【英文标题】:Returning from java method before all threads are done 【发布时间】: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
中打印一些东西来测试其他方法是否返回。
【参考方案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 修正了这个错字!)以上是关于在所有线程完成之前从 java 方法返回的主要内容,如果未能解决你的问题,请参考以下文章
Java Concurrency - 浅析 CountDownLatch 的用法
Java线程池,isShutDownisTerminated的作用与区别