invokeAll()vs Guava ListenableFuture + addCallback()

时间:2013-07-26 17:05:53

标签: java multithreading concurrency threadpool guava

我想知道使用ListenableFuture+addCallback()代替invokeAll()会有什么好处,以防我只对一次获得所有任务的结果感兴趣。

invokeAll()会隐藏任何抛出的异常吗?如果我使用invokeAll(),我需要处理其他任何事情,因为addCallback()提供了onSuccess()onFailure()方法,但invokeAll()没有这样的功能。

提前致谢!

2 个答案:

答案 0 :(得分:10)

使用ListenableFuture,您可以提交任意数量的任务,然后将这些任务中的ListenableFuture传递给Futures.allAsList,获取另一个ListenableFuture,这些任务将在所有任务已完成。还有Futures.successfulAsList,即使某些任务失败也会成功,并为每个失败的任务提供null结果。

然后你可以阻止当前线程等待那些结果(使用普通Future.get()),或者你可以添加一个监听器/回调函数,如果你不想要/不需要它们就会被调用阻止当前线程。

示例:

ListeningExecutorService executor = ...
List<Callable<Foo>> tasks = ...

List<ListenableFuture<Foo>> futures = Lists.newArrayList();
for (Callable<Foo> task : tasks) {
  futures.add(executor.submit(task));
}

final ListenableFuture<List<Foo>> resultsFuture
    = Futures.allAsList(futures);

// block until all tasks are done
List<Foo> results = resultsFuture.get();

// or add a callback to get called when the tasks complete
Futures.addCallback(resultsFuture, new FutureCallback<List<Foo>>() {
  @Override public void onSuccess(List<Foo> results) {
    // ...
  }

  @Override public void onFailure(Throwable throwable) {
    // ...
  }
}, someExecutor);

答案 1 :(得分:0)

ExecutorService.invokeAll()返回Futures<?>列表,然后您可以遍历此列表并执行future.get(),如果在计算过程中发生异常,则会抛出异常,如果没有错误,则会抛出结果。

这里的例子是:

class SecondFailTask implements Callable<Integer> {
    private static volatile int counter = 0;
    @Override
    public Integer call() throws Exception {
        counter++;
        if (counter == 2){
            throw new RuntimeException("Fail");
        } else {
            return counter;
        }
    }

    public static void main(String[] args) throws Exception{
        ExecutorService e = Executors.newSingleThreadExecutor();
        List<SecondFailTask> tasks = Arrays.asList(new SecondFailTask(),new SecondFailTask(),new SecondFailTask());
        List<Future<Integer>> futures =  e.invokeAll(tasks);
        for (Future<Integer> future : futures){
            try {
                System.out.println("Counter is " + future.get());
            }catch (ExecutionException ex){
                System.out.println(ex.getCause());
            }
        }
    }

输出是:

Counter is 1
java.lang.RuntimeException: Fail
Counter is 3

我不确定是否有办法立即获取所有任务的结果,因为据我所知onSuccess()onFailure()在每次任务计算后执行,这样收集结果将是技巧(带有一些全局变量)。我更愿意使用ExecutorService.invokeAll(),但我不是番石榴专家,我可能会错过一些东西。