ExecutorService 等待所有 Future 完成

ExecutorService wait for all Future to complete

我有以下 ExecutorService 代码。

try{
    ExecutorService executor = Executors.newFixedThreadPool(5);
    List<Callable<String>> taskList = new ArrayList<Callable<String>>(5);
    for(int i=1;i<=5;i++){
        taskList.add(new SimpleTask());
    }

    List<Future<String>> list =  executor.invokeAll(taskList);
    executor.shutdown();
    System.out.println(list.get(0).get());
    System.out.println("Exit");
}catch(Exception e){
    e.printStackTrace();
}

class SimpleTask implements Callable<String> {
    @Override
    public String call() throws Exception {     
        return new Date().toString();
    }
}

我想知道list.get(0).get()会等待所有任务完成吗?

不,代码不会等待每个任务完成。通过调用 list.get(0).get(),您将检索第一个可选调用 get(),它将根据 documentation 阻塞线程。

要等待每个可调用完成,您需要遍历列表并查看是否全部完成。当然,您可以通过对它们中的每一个调用 get() 来做到这一点,但是您会一直阻塞主线程。我自己更喜欢在等待其他线程执行时能够做一些事情。

使用 Java 8 个流的示例:

// filter if any future is not done yet
while ( list.stream().anyMatch(i->!i.isDone()) )
{
  // Do whatever you want parallel to the evaluation of the Future objects

  // example
  System.err.println( "Not all are done yet." );
}
// process your results

// example:
String[] results = list.stream().map( Main::evalGet ).toArray(String[]::new);

注意:priavte static <T> TevalGet(Future<T> fu) 只是一个包装函数,用于保持 lambda 表达式干净的异常处理,看起来类似于:

private static <T> T evalGet( Future<T> fu )
  {
    T obj = null;
    try
    {
      obj = fu.get();
    }
    catch ( InterruptedException | ExecutionException e )
    {
      e.printStackTrace();
    }
    return obj;
  }

这里的代码不会在执行 list.get(0).get() 语句时等待,而是 executor.invokeAll(taskList) 语句,因为 invokeAll() 方法本身会等待所有线程的复杂化。

了解更多