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

时间:2013-11-18 20:44:08

标签: java multithreading concurrency executorservice

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

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

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

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

6 个答案:

答案 0 :(得分:28)

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

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

您可以(并且应该)通过shutdownExecutorService手动关闭shutdownNow

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

答案 1 :(得分:6)

  

我希望我的程序/流程在所有工作完成后立即停止。但根据我的日志,它需要另外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 after submitting all of your workers
threadPool.shutdown();

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

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

答案 2 :(得分:3)

来自Executors.newCachedThreadPool()的{​​{3}}:

  

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

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

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

答案 3 :(得分:3)

基本上在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) {
  ...
}

答案 4 :(得分:0)

用于ExecutorService的多线程 解决方案是 threadPool.shutdown();

答案 5 :(得分:0)

这是由于keepAliveTime = 60L,timeunit = TimeUnit.SECONDS和corePoolSize = 0 *的组合:当线程完成任务时,它不会立即终止,可能会在keepAliveTime中等待新任务。

 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

*如果核心poolSize!= 0,请参见ThreadPoolExecutor的allowCoreThreadTimeOut()方法

**等待时间取决于池中当前正在运行的线程数量,corePoolSize和maximumPoolSize的组合