如何使用invokeAll()让所有线程池执行任务?
ExecutorService pool=Executors.newFixedThreadPool(7); List<Future<Hotel>> future=new ArrayList<Future<Hotel>>();
List<Callable<Hotel>> callList = new ArrayList<Callable<Hotel>>();
for(int i=0;i<=diff;i++){
String str="2013-"+(liDates.get(i).get(Calendar.MONTH)+1)+"-"+liDates.get(i).get(Calendar.DATE);
callList.add(new HotelCheapestFare(str));
}
future=pool.invokeAll(callList);
for(int i=0;i<=future.size();i++){
System.out.println("name is:"+future.get(i).get().getName());
}
现在我想invokeAll
在进入for循环之前集中所有任务,但是当我运行此程序时,for循环会在invokeAll
此之前执行并引发此异常:
java.util.concurrent.ExecutionException: java.lang.NullPointerException at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source) at
java.util.concurrent.FutureTask.get(Unknown Source) at
com.mmt.freedom.cheapestfare.TestHotel.main(TestHotel.java:65)
Caused by: java.lang.NullPointerException at
com.mmt.freedom.cheapestfare.HotelCheapestFare.getHotelCheapestFare(HotelCheapestFare.java:166)
at com.mmt.freedom.cheapestfare.HotelCheapestFare.call(HotelCheapestFare.java:219)
at com.mmt.freedom.cheapestfare.HotelCheapestFare.call(HotelCheapestFare.java:1)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) atjava.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run
回答:
一种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) at
java.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
它得到了Future
S作为他们变得可用,然后我提交任务了ExecutorCompletionService
。
这样一来,您就可以在失败后立即获得失败的任务,而不必等待所有任务一起失败。
唯一的麻烦是,由于现在所有事物都是异步的,因此很难告诉轮询线程所有任务都已完成。在这种情况下,我已经知道将要提交100个任务,因此只需要轮询100次即可。更通用Future
的submit
方法是也从方法中收集s
,然后循环遍历以查看是否已完成。
以上是 如何使用invokeAll()让所有线程池执行任务? 的全部内容, 来源链接: utcz.com/qa/428323.html