一种
ExecutorService工作方式是,当您调用
invokeAll它时,它等待所有任务完成:
执行给定的任务,并在所有任务完成时返回保存其状态和结果的期货列表。Future.isDone()对于返回列表的每个元素为true。
请注意,已完成的任务可能已正常终止或引发了异常而终止
。如果在进行此操作时修改了给定的集合,则此方法的结果不确定。1(强调)
这意味着您的任务已全部完成,但有些可能会引发异常。此异常是
Future-调用的一部分,
get导致将异常重新包装在
ExecutionException。
从你的stacktrack
java.util.concurrent.ExecutionException: java.lang.NullPointerException atjava.util.concurrent.FutureTask$Sync.innerGet(Unknown Source) atjava.util.concurrent.FutureTask.get(Unknown Source) at^^^ <-- from get
您可以看到确实如此。使用NPE,您的任务之一失败了。在
ExecutorService捕捉到的异常,并抛出一个告诉你这件事
ExecutionException,当你调用
Future.get。
现在,如果您要在完成任务时执行任务 ,则
需要一个
ExecutorCompletionService。这样
BlockingQueue可以使您在完成任务时轮询任务。
public static void main(String[] args) throws Exception { final ExecutorService executorService = Executors.newFixedThreadPool(10); final ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(executorService); executorService.submit(new Runnable() { @Override public void run() { for (int i = 0; i < 100; ++i) { try { final Future<String> myValue = completionService.take(); //do stuff with the Future final String result = myValue.get(); System.out.println(result); } catch (InterruptedException ex) { return; } catch (ExecutionException ex) { System.err.println("TASK FAILED"); } } } }); for (int i = 0; i < 100; ++i) { completionService.submit(new Callable<String>() { @Override public String call() throws Exception { if (Math.random() > 0.5) { throw new RuntimeException("FAILED"); } return "SUCCESS"; } }); } executorService.shutdown();}在这个例子中,我有一个任务调用
take上
ExecutorCompletionService它得到了
FutureS作为他们变得可用,然后我提交任务了
ExecutorCompletionService。
这样一来,您就可以在失败后立即获得失败的任务,而不必等待所有任务一起失败。
唯一的麻烦是,由于现在所有事物都是异步的,因此很难告诉轮询线程所有任务都已完成。在这种情况下,我已经知道将要提交100个任务,因此只需要轮询100次即可。更通用
Future的
submit方法是也从方法中收集s
,然后循环遍历以查看是否已完成。



