完成所有ExecutorService任务后,程序不会立即终止

我将一堆可运行的对象放入ExecutorService:

// simplified content of main method ExecutorService threadPool = Executors.newCachedThreadPool(); for(int i = 0; i < workerCount; i++) { threadPool.execute(new Worker()); } 

我希望我的程序/流程在所有工人完成后立即停止。 但根据我的日志,它需要另外20-30秒才能发生。 工人们没有分配任何资源,事实上,他们现在什么都不做。

不要误会我的意思,这对我来说不是一个至关重要的问题,我只是想了解发生了什么,我想知道这是否是正常行为。

Executors.newCachedThreadPool()对其ThreadFactory使用Executors.defaultThreadFactory()defaultThreadFactory的javadocs说“每个新线程都是作为非守护进程线程创建的”(强调添加)。 因此,为newCachedThreadPool创建的线程是非守护进程。 这意味着它们会阻止JVM自然退出(“自然地”我的意思是你仍然可以调用System.exit(1)或者杀死程序以使JVM停止)。

应用程序完成的原因是在newCachedThreadPool创建的每个线程超时并在一段时间不活动后自行关闭。 当最后一个自己关闭时,如果你的应用程序没有任何非守护程序线程,它将退出。

您可以(并且应该)通过shutdownshutdownNow手动shutdown ExecutorService

另请参阅JavaDoc for Thread ,其中讨论了守护进程。

我希望我的程序/流程在所有工人完成后立即停止。 但根据我的日志,它需要另外20-30秒才能发生。 工人们没有分配任何资源,事实上,他们现在什么都不做。

问题是您没有关闭ExecutorService 。 将所有作业提交到服务后, 必须关闭服务,否则JVM将不会终止,除非其中的所有线程都是守护程序线程。 如果不关闭线程池,那么与ExecutorService关联的任何线程(如果不是守护进程)将阻止JVM完成。 如果您已将任何任务提交到缓存的线程池,那么您必须等待线程超时并在JVM完成之前获得收获。

 ExecutorService threadPool = Executors.newCachedThreadPool(); for(int i = 0; i < workerCount; i++) { threadPool.execute(new Worker()); } // you _must_ do this threadPool.shutdown(); 

将线程作为守护进程启动很可能不是您想要做的,因为您的应用程序可能任务完成之前停止并且所有任务将在此时立即终止。 在我们的生产代码中使用ExecutorService类的178次中,只有2个作为守护程序线程启动。 其余的都正常关闭。

如果您需要强制ExecutorService在应用程序退出时停止,则使用shutdownNow()并正确处理线程中断标志。

来自Executors.newCachedThreadPool()的javadoc :

未使用60秒的线程将终止并从缓存中删除。

如果您知道不会向其提交任何新任务,那么在ExecutorService上调用shutdown()通常是个好主意。 然后队列中的所有任务都将完成,但服务将立即关闭。

(或者,如果您不关心所有任务是否完成 – 例如,如果他们正在处理一旦您的主UI消失后无关的后台计算 – 那么您可以创建一个ThreadFactory ,将该池中的所有线程设置为守护进程)。

基本上在ExecutorService上调用shutdown()然后调用awaitTermination():

 ExecutorService taskExecutor = Executors.newFixedThreadPool(4); while(...) { taskExecutor.execute(new MyTask()); } taskExecutor.shutdown(); try { taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { ... } 

对于ExecutorService的multithreading解决方案是threadPool.shutdown();