ExecutorService等待所有Future完成

时间:2018-04-12 06:35:30

标签: java executorservice

我有以下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()会等待所有任务完成吗?

3 个答案:

答案 0 :(得分:4)

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

了解详情Answer

答案 1 :(得分:1)

是Future get()方法阻止执行并在继续之前等待结果。

  

get()如果需要等待计算完成,然后   检索其结果。

因此,您的代码list.get(0).get()将等待任务的执行,然后将其打印出来。但这仅适用于第一个任务,因为您只为列表中的第一个Future调用get()方法。如果您想等待所有任务,您应该遍历列表。

您可以通过修改代码来测试:

public class HelloWorld
{
    public static void main(String[] args)
  {
     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(i!=1));
        }
        System.out.println("Before:"+new Date().toString());
        List<Future<String>> list =  executor.invokeAll(taskList);
        executor.shutdown();
        System.out.println(list.get(0).get()); //Change that to 1 to see the difference
        System.out.println("Exit");
    }catch(Exception e){
        e.printStackTrace();
    }
  }

}

class SimpleTask implements Callable<String> {

    boolean wait=false;
    public SimpleTask(boolean wait){           
        this.wait=wait;
    }
    public String call() throws Exception {     
         if(wait){
             Thread.sleep(5000);
         }
        return ""+wait+" - "+new Date().toString();
    }
}

通过向除第一个和正在运行的所有任务添加延迟,您可以看到 运行程序时System.out.println(list.get(0).get());执行相同的秒。如果你做System.out.println(list.get(1).get()); - &gt;它在5秒后执行。这可以告诉你第一个get(0)只等待第一个执行的未来

答案 2 :(得分:0)

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

要等待每个callable完成,您需要遍历列表并查看是否所有都已完成。当然你可以通过在每一个上调用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;
  }