ExecutorService 的 shutdown() 不会等到所有线程都完成



我有一个代码,其中4个线程同时运行。我想等到这4个线程全部完成。只有在那之后才能继续应用程序流。

我尝试了两种方法:

  1. Thread#join(),此方法按预期工作。join()之后的代码仅在所有线程完成后执行
  2. ExecutorService#shutdown(),此技术允许执行shutdown()之后的代码,即使不是所有线程都完成

代码示例:

ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
for (int i = 0; i < cpuCoresNum; i++) {
    service.submit(() -> {
        try {
            foo(); // some long execution function
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
}
service.shutdown();
System.out.println("We're done! All threads are finished!");

为什么submit()shutdown()不等到所有线程都完成并打印«我们完成了!所有线程都已完成!»呼叫service.shutdown();之后?

答案在ExecutorService.shutdown() Javadoc:中可用

此方法不等待以前提交的任务完成执行。使用awaitTermination执行此操作。

如果你想等待线程完成工作,你有以下选项:

  • 获取submit()返回的Future实例,并在每个Future实例上调用get()
  • service上调用shutdown之后,在service上调用awaitTermination,直到返回true
  • 不要在service上调用submit,而是将Runnable实例添加到java.util.List中,并将此列表传递给在service上调用的invokeAll方法

ExecutorService oracle文档页面推荐方式:

 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();
   }

shutdown():启动有序关闭,执行以前提交的任务,但不接受新任务。

shutdownNow():尝试停止所有正在执行的任务,停止处理等待的任务,并返回等待执行的任务列表。

在上面的例子中,如果您的任务需要更多的时间来完成,您可以将if条件更改为while条件

更换

if (!pool.awaitTermination(60, TimeUnit.SECONDS))

带有

 while(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
     Thread.sleep(60000);
 }  

感谢@Adam Siemion的建议,这里是最后一个代码:

ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
int itNum = 1;
for (int i = 0; i < cpuCoresNum; i++) {
    int treadID = itNum++;
    service.submit(() -> {
        Thread.currentThread().setName("Thread_#" + treadID);
        try {
            foo();
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
}
// wait until all threads will be finished
service.shutdown();
try {
    service.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
    e.printStackTrace();
}

相关内容

  • 没有找到相关文章

最新更新