如何使用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:6‌​5)

Caused by: java.lang.NullPointerException at

com.mmt.freedom.cheapestfare.HotelCheapestFare.getHotelCheap‌estFare(HotelCheapes‌​tFare.java:166)

at com.mmt.freedom.cheapestfare.HotelCheapestFare.call(HotelChe‌​apestFare.java:219)

at com.mmt.freedom.cheapestfare.HotelCheapestFare.call(HotelChe‌​apestFare.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(Unknow‌​n Source)

at java.lang.Thread.run

回答:

一种ExecutorService工作方式是,当您调用invokeAll它时,它等待所有任务完成:

执行给定的任务,并在所有任务完成时返回保存其状态和结果的期货列表。Future.isDone()对于返回列表的每个元素为true。

。如果在进行此操作时修改了给定的集合,则此方法的结果不确定。1(强调)

这意味着您的任务已全部完成,但有些可能会引发异常。此异常是Future-调用的一部分,get导致将异常重新包装在ExecutionException

从你的stacktrack

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

^^^ <-- 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();

}

在这个例子中,我有一个任务调用takeExecutorCompletionService它得到了FutureS作为他们变得可用,然后我提交任务了ExecutorCompletionService

这样一来,您就可以在失败后立即获得失败的任务,而不必等待所有任务一起失败。

唯一的麻烦是,由于现在所有事物都是异步的,因此很难告诉轮询线程所有任务都已完成。在这种情况下,我已经知道将要提交100个任务,因此只需要轮询100次即可。更通用Futuresubmit方法是也从方法中收集s

,然后循环遍历以查看是否已完成。

以上是 如何使用invokeAll()让所有线程池执行任务? 的全部内容, 来源链接: utcz.com/qa/428323.html

回到顶部