在Java中等待ThreadPoolExecutor完成线程的最佳方法是什么?

3
我正在使用Java中的ThreadPoolExecutor来执行多个线程,完成后需要做一些事情并等待。
因此,我想问什么是最好的方法来达到这个目的?
我用的方式正确吗?
threadPool.shutdown();

boolean loop = true;
Integer x = threadPool.getPoolSize();
while (threadPool.getPoolSize() != 0) {
}
2个回答

1

Shutdown会启动一个有序的关机过程,在此过程中,之前提交的任务将被执行,但不会接受新的任务。

    executor.shutdown();
    System.out.println("All tasks submitted...No new tasks will be admitted");

然而,我强烈建议使用awaitTermination,因为这将允许当前线程在关闭请求后阻塞,直到所有任务完成执行,或超时发生,或当前线程被中断,以先发生的为准。

    try {
        executor.awaitTermination(3, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

编辑:

 The runState provides the main lifecyle control, taking on values:

 *   RUNNING:  Accept new tasks and process queued tasks
 *   SHUTDOWN: Don't accept new tasks, but process queued tasks
 *   STOP:     Don't accept new tasks, don't process queued tasks,
 *             and interrupt in-progress tasks
 *   TIDYING:  All tasks have terminated, workerCount is zero,
 *             the thread transitioning to state TIDYING
 *             will run the terminated() hook method
 *   TERMINATED: terminated() has completed

这些值之间的数字顺序很重要,以允许有序比较。runState随时间单调递增,但不需要达到每个状态。 转换如下:
RUNNING -> SHUTDOWN 在shutdown()被调用时(可能是finalize()中隐式调用)
(RUNNING或SHUTDOWN) -> STOP 在shutdownNow()被调用时
SHUTDOWN -> TIDYING 当队列和池都为空时
STOP -> TIDYING 当池为空时
TIDYING -> TERMINATED 当terminated()钩子方法完成时。等待awaitTermination()的线程将在状态达到TERMINATED时返回。
检测从SHUTDOWN到TIDYING的转换不太直接,因为在SHUTDOWN状态期间队列可能在非空和空之间变为空,反之亦然,但仅当看到它为空后,我们才能终止并看到workerCount为0。
当你调用getPoolSize()方法时,它会检查线程池处于TIDYING状态时的状态。因此,我认为正确的检查应该是针对TERMINATED状态。尽管如果你没有实现terminated()方法,结果仍然相同。

两个原因:1. while loop 在线程池执行完成之前会一直占用 CPU,而 awaitTermination 不会如此。2. 当您使用 getPoolSize() 时,执行程序的状态尚未终止。尽管您可能还没有实现 terminated() 调用,因此您应该没问题。但对于第一个原因,我建议使用 awaitTermination 而不是 while 循环。 - Suparna
但是当只使用try { executor.awaitTermination(3, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); }时,它不能等待所有线程完成。主进程将在此之后继续运行代码。似乎必须使用while来阻止主进程在线程完成之前继续运行。 - jsohpill
抱歉,我在其中一个示例中使用了它,我想等待3秒钟。您可以将其更改为:executor.awaitTermination(3, TimeUnit.DAY); - Suparna
谢谢你的帮助。我仍然使用while循环,因为我必须等待所有线程完成,并且我使用awaitTermination。尝试: try { while (!threadPool.awaitTermination(1, TimeUnit.SECONDS)) { } } catch (InterruptedException e) { e.printStackTrace(); } - jsohpill
没问题。只要你觉得这些信息有用,你可以给回答点赞,并选择最佳回答。同时,你还会因为关闭问题而获得积分。 - Suparna

1

如果您想优雅地等待,请参考下面问题中的解决方案:

如何在Java中等待多个任务完成?

如果您没有使用任何这些方法(invokeAllCountDownLatch),并且提交了作业并等待执行程序完成任务,请参考

如何强制关闭Java ExecutorService?

在这种情况下的基本代码片段:

void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接