【问题标题】:ExecutorService - How to wait for completition of all tasks in non-blocking styleExecutorService - 如何以非阻塞方式等待所有任务的完成
【发布时间】:2015-08-28 14:27:45
【问题描述】:

我在 Java Web 服务器应用程序 中使用ExecutorService 以并行方式执行一些计算任务,然后使用awaitTermination() 调用shutdown() 以等待所有任务完成。整个计算有时可能需要几十分钟。

事情是awaitTermination() 方法阻塞主线程直到超时(或中断)但我只想启动任务并立即响应客户端和之后所有任务的竞争都会关闭服务(遵循始终关闭线程池的约定)。

所以我的问题是,有没有一种方法可以在所有任务完成后得到通知,以便我可以调用shutdown() 方法?听众什么的..

谢谢!

【问题讨论】:

标签: java multithreading web-applications executorservice


【解决方案1】:

您正在尝试解决一个不存在的问题。考虑documentation of ExecutorService.shutdown()

启动有序关闭,其中执行先前提交的任务,但不会接受新任务。 …

此方法不等待之前提交的任务完成执行。

换句话说,只需调用shutdown() 就可以满足您的所有需求

  • 它完成了之前提交的所有任务
  • 它启动关机
  • 它不等待

唯一的障碍是你打电话给awaitTermination,尽管你不想等待,这有一个简单的解决方案:不要打电话awaitTermination

之所以出现混淆,是因为在您的问题中,您问的是“如何在所有任务完成后通知我,以便我可以调用 shutdown() 方法”,但这与您在代码中实际执行的操作相矛盾。您正在调用awaitTermination after shutDown,因此您不是为了启动关闭而等待,而是首先启动shutdown 并等待其完成,这是@987654330 的目的@,等待关机完成


一句话,提交后调用shutDown,以便在所有提交的作业完成后关闭服务,不要调用awaitTermination,除非你真的想等待终止。

【讨论】:

  • 谢谢,我被 API 文档中的这句话弄糊涂了:This method does not wait for previously submitted tasks to complete execution. 我认为所有提交和未完成的任务都会在执行前终止,但现在我只需要调用 shutdown() 我就知道了得到想要的行为。谢谢!
  • 我还有一个问题:有没有办法知道执行队列何时变空,最后一个任务执行何时结束?
  • 这是两个不同的东西。队列包含尚未开始执行的作业(您可以查看getQueue().isEmpty())。但是空队列并不意味着没有一些作业仍在运行。您可以查看getActiveCount(),但请记住,这是一个估计值。完成所有工作是awaitTermination 所暗示的,完成所有工作(加上终止线程)。如果你想等待服务空闲,而不终止它,恐怕标准ThreadPoolExecutor没有预见到。
【解决方案2】:

感谢VGR 的评论,我通过创建另一个Thread 解决了我的问题,我在其中包装了我现有的代码,如下所示:

Thread thread = new Thread(() -> {
    ExecutorService service = Executors.newCachedThreadPool();

    collection.forEach(item -> service.submit(() -> {
            // some computational work
        });

    try {
        service.shutdown()
        service.awaitTermination(2, TimeUnit.HOURS);
    catch (InterruptedException iEx) {
        // handle exception
    }
});

thread.start();

return ResponseToClient();

【讨论】:

  • 这没有任何意义,请参阅@Holger 解释
  • @AdamSkywalker 我认为他没有正确提出他的问题,他实际上把自己搞砸了 awaitTermination()。他的要求是异步启动任务并在所有任务完成后关闭 ExecutorService。因此,在新线程中运行他的 ExecutorService 对他有用,而且他不需要 awaitTermination() 正如 Holger 正确解释的那样。
  • @hagrawal 它可以在没有 awaitTermination() 调用的情况下在主线程中完成 - 任务将异步运行,服务将在最后关闭。
  • @AdamSkywalker 是的,我同意,这就是为什么我说他搞砸了 awaitTermination(),他只需要异步行为,而 shutdown() 已经做得很好了。
  • @hagrawal 是的,你们是对的,我对 API 文档中的一句话感到困惑,无论如何感谢您的帮助。
猜你喜欢
  • 2011-03-17
  • 2021-05-26
  • 2021-08-14
  • 2018-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多