【问题标题】:invokeAll() vs Guava ListenableFuture+addCallback()invokeAll() 与 Guava ListenableFuture+addCallback()
【发布时间】:2013-07-26 17:05:53
【问题描述】:

我想知道使用ListenableFuture+addCallback() 而不是invokeAll() 的优势是什么,以防我只对一次获得所有任务的结果感兴趣。

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

提前致谢!

【问题讨论】:

  • 谁强迫你使用ListenableFuture
  • 不强迫我,我的问题是出于兴趣,想知道我是否遗漏了什么。

标签: java multithreading concurrency threadpool guava


【解决方案1】:

使用ListenableFuture,您可以提交任意数量的任务,然后将这些任务中的ListenableFutures 传递给Futures.allAsList,获得另一个ListenableFuture,该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);

【讨论】:

  • 你能给我一些代码吗?当然可以google,但是之前尝试的时候没有得到任何相关代码。
  • @Tingya:添加了一个例子。
  • 谢谢!现在这更有意义了!
  • @ColinD 我也有关于番石榴的问题ListenableFuture。如果可能的话,你能否回顾一下我的设计并帮助我澄清我的一些疑问以及我应该如何处理它们?我最近开始使用 Guava ListenableFuture,我非常喜欢,但对如何有效使用它们有些困惑。
  • @ColinD 嘿,你在附近进行快速聊天。这将有助于我清楚地了解如何正确使用 guava ListenableFuture。我正在尝试在我的库中实现同步和异步实现,所以我使用的是 Guava 提供的未来,但需要一些建议。我会在这个chat room。如果可能,您可以随时加入。
【解决方案2】:

ExecutorService.invokeAll() 返回Futures&lt;?&gt; 的列表,然后您可以遍历此列表并执行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(),但我不是番石榴专家,我可能会错过一些东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 2023-03-31
    • 2015-06-02
    相关资源
    最近更新 更多