2009-07-31 63 views
9

根据Brian Goetz的Java Concurrency in Practice 在所有(非守护进程)线程终止前,JVM无法退出,因此未能关闭Executor可能会阻止JVM退出。如何在退出应用程序时关闭所有执行程序?

即,如果有Executors,System.exit(0)不一定像预期的那样工作。看起来有必要对所有包含执行程序的类添加某种类型的方法,然后在应用程序即将终止时调用它们。这是唯一的方法,还是有某种快捷方式来关闭所有的执行程序?

+0

我很怀疑Executor和Runnable。我删除了我的答案,因为它没有多大意义。 @skaffman有我的投票。 – 2009-07-31 10:26:00

回答

14

没有捷径可以做到这一切,没有。此外,您应该拨打shutdownNow()而不是shutdown(),否则您可能会等待一段时间。

我想你应该做的是在创建Executor时将其注册到中心位置。然后,在关闭时,只需在该中央对象上调用shutdown(),这又可以终止每个注册的执行程序。

如果您使用Spring,那么您可以利用其工厂bean来创建和管理执行程序。这包括在应用程序退出时优雅地关闭它们,并节省您自己管理它们。

+0

中央登记册似乎是一个合理的选择。有趣的是,java.util.concurrent不包括这样的。 – 2009-07-31 10:11:09

+0

Executors只是一堆静态信息,这使得很难将其隐藏在注册界面后面而不复制数十个方法签名,这也是一个耻辱。 – skaffman 2009-07-31 10:16:24

0

也许他的意思是说,JVM不能自行停止,直到nondaemon线程完成。它像从Java SomeClass这样的命令运行一个简单的类,并在执行main方法JVM后停止。

System.exit是JVM终止命令,即使守护程序线程正在运行,JVM也会关闭。

+1

正如Goetz写道,* nondaemon *线程可以阻止JVM退出。其实我已经经历过这个。调试器显示该应用程序可能会阻塞到系统。无限地退出(0),但它似乎是不确定的行为。通常它不会阻塞,但有时它会阻塞。 – 2009-07-31 10:06:33

5

您还可以提供一个ThreadFactory实现,将创建的线程标记为守护线程。我更喜欢一个干净的关闭机制(使用生命周期方法),但有些情况下,如果适当,您不需要保证未完成任务的状态/完成。

7

默认情况下,执行程序将只创建非守护程序线程。您可以通过向Executor提供您自己的ThreadFactory来覆盖它。这里有一个例子:

class DaemonThreadFactory implements ThreadFactory { 
    public Thread newThread(Runnable r) { 
    Thread t = new Thread(r); 
    t.setDaemon(true); 
    return t; 
    } 
} 

要谨慎,但是,因为JVM将退出马上即使这些线程都在忙着做无用功!

8

装饰执行人与com.google.common.util.concurrent.MoreExecutors#getExitingExecutorService

@Beta 
public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor, 
             long terminationTimeout, 
             TimeUnit timeUnit) 

给定的ThreadPoolExecutor转换到应用程序完成时离开一个ExecutorService的。它通过使用守护程序线程并添加关闭挂钩来等待它们完成。

这主要是针对固定线程池。请参阅Executors.newFixedThreadPool(int)。

相关问题