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

我有一个代码,其中4个线程同时运行。 我想等到所有这4个线程都完成。 只有在那之后继续app流程。

我尝试了两种方法:

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

代码示例:

 ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum); for (int i = 0; i  { 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上调用shutdownservice调用awaitTermination ,直到它返回true
  • 而不是在service上调用submitRunnable实例添加到java.util.List并将此列表传递给在service调用的invokeAll方法

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

从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 (!pool.awaitTermination(60, TimeUnit.SECONDS)) 

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