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

时间:2016-04-02 16:58:53

标签: java multithreading concurrency executorservice java-threads

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

我尝试了两种方法:

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

    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();
    • 调用后立即完成!»

3 个答案:

答案 0 :(得分:8)

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

  

此方法不会等待先前提交的任务完成执行。使用awaitTermination来做到这一点。

如果您想等待线程完成工作,您可以选择以下选项:

  • Future返回submit()个实例,并在每个get()个实例上调用Future
  • shutdownservice致电awaitTermination后致电service,直至其返回true
  • 而不是在submit上调用service,而是将Runnable个实例添加到java.util.List,并将此列表传递给invokeAll上调用的service方法}

答案 1 :(得分:1)

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

答案 2 :(得分:1)

来自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);
 }