Guava学习之ListenableFuture

ListenableFuture

并发是一个很难的问题,但是通过使用强大的和简单的抽象,它被大大简化了。方便起见, Guava 继承了JDK的 Future 接口 实现了 ListenableFuture.

我们强烈建议在代码中总是使用 ListenableFuture 代替 Future, 因为:

  • 大部分的 Futures 方法都需要它.
  • 这比之后改变为 ListenableFuture 更容易.
  • 提供的工具方法不需要 Future  与 istenableFuture 的变体在方法中.

 

Interface

一个传统的 Future 表示异步计算的结果: 这可能是一个完成或尚未完成的计算结果。  Future 可以是正在进行的计算的程序的承诺在将来提供我们结果。

ListenableFuture 允许去注册回调在计算完成后执行,或者计算已经完成就立即执行。这种简单的添加使得有可能有效地支持基本的Future接口无法支持的许多操作。

 ListenableFuture 的基础添加操作是 addListener(Runnable, Executor), 当指定的Future计算完成,特殊的Runnable将运行在指定的Executor上

Adding Callbacks

大多数人更愿意使用 Futures.addCallback(ListenableFuture<V>, FutureCallback<V>, Executor), 或者当返回非常快且重要时使用版本默认的 MoreExecutors.directExecutor()。  FutureCallback<V> 实现了两个方法:

 

Creation

对应于 JDK的初始化一步计算的方法 ExecutorService.submit(Callable) , Guava 提供了 ListeningExecutorService 接口, 它将在ExecutorService返回一个正常 Future的任何地方返回一个 ListenableFuture . 将 ExecutorService 转换为ListeningExecutorService, 可以使用 MoreExecutors.listeningDecorator(ExecutorService).

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)); ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() { 
   public Explosion call() { 
     return pushBigRedButton(); 
   } 
}); 

Futures.addCallback(explosion, new FutureCallback<Explosion>() {
   // we want this handler to run immediately after we push the big red button! 
   public void onSuccess(Explosion explosion) { 
       walkAwayFrom(explosion); 
   } 
   public void onFailure(Throwable thrown) {
       battleArchNemesis(); // escaped the explosion! 
   } 
});

或者, 如果想基于FutureTask 转换 , Guava  提供了 ListenableFutureTask.create(Callable<V>)ListenableFutureTask.create(Runnable, V). 不像 JDK, ListenableFutureTask 不意味着直接继承。

如果你喜欢一个抽象,在其中你设置future 的价值而不是实现一个方法来计算这个值,,考虑继承AbstractFuture<V> 或者直接使用SettableFuture .

如果必须从其他的API将 Future 转换为 ListenableFuture, 只能选择JdkFutureAdapters.listenInPoolThread(Future)  最好修改源代码返回 ListenableFuture.

 

Application

使用 ListenableFuture 最重要的原因是其提供了复杂的异步操作链。

ListenableFuture<RowKey> rowKeyFuture = indexService.lookUp(query); 
AsyncFunction<RowKey, QueryResult> queryFunction = new AsyncFunction<RowKey, QueryResult>() { 
    public ListenableFuture<QueryResult> apply(RowKey rowKey) { 
        return dataService.read(rowKey); 
    } 
}; 

ListenableFuture<QueryResult> queryFuture = Futures.transformAsync(rowKeyFuture, queryFunction, queryExecutor);

许多其他的操作可以有效地支持 ListenableFuture 不能单独的支持 Future .不同的操作可以由不同的执行器执行,单个ListenableFuture可以有多个操作等待执行。

Method Description See also
transformAsync(ListenableFuture<A>, AsyncFunction<A, B>, Executor)* Returns a new ListenableFuture whose result is the product of applying the given AsyncFunction to the result of the given ListenableFuture. transformAsync(ListenableFuture<A>, AsyncFunction<A, B>)
transform(ListenableFuture<A>, Function<A, B>, Executor) Returns a new ListenableFuture whose result is the product of applying the given Function to the result of the given ListenableFuture. transform(ListenableFuture<A>, Function<A, B>)
allAsList(Iterable<ListenableFuture<V>>) Returns a ListenableFuture whose value is a list containing the values of each of the input futures, in order. If any of the input futures fails or is cancelled, this future fails or is cancelled. allAsList(ListenableFuture<V>...)
successfulAsList(Iterable<ListenableFuture<V>>) Returns a ListenableFuture whose value is a list containing the values of each of the successful input futures, in order. The values corresponding to failed or cancelled futures are replaced with null. successfulAsList(ListenableFuture<V>...)

* 一个 AsyncFunction<A, B> 提供一个方法, ListenableFuture<B> apply(A input). 其可以被用来异步的转换一个值。

List<ListenableFuture<QueryResult>> queries; 
// The queries go to all different data centers, but we want to wait until they're all done or failed. 

ListenableFuture<List<QueryResult>> successfulQueries = Futures.successfulAsList(queries); 

Futures.addCallback(successfulQueries, callbackOnSuccessfulQueries);

 

Avoid nested Futures

在例子中代码访问了传统的接口以及返回一个 Future, 可能结束语嵌套的 Futures. 例如:

executorService.submit(new Callable<ListenableFuture<Foo>() { 
   @Override 
   public ListenableFuture<Foo> call() { 
     return otherExecutorService.submit(otherCallable); 
   } 
});

将返回 ListenableFuture<ListenableFuture<Foo>>. 这个代码不正确, 因为如果一个 cancel 在输出的路径,并完成在 外部的 future, 那么取消将不会传播进 future中。代码也犯了一个经常犯的错,检查失败使用其他future的get()或监听器。至少应该关心的是从otherCallable 抛出的异常将被抑制。为了避免上面的情况, 所有的 Guava future-handling 方法 (一些来自 JDK) 都有 *Async 版本安全的打开异常嵌套 - transform(ListenableFuture<A>, Function<A, B>, Executor) and transformAsync(ListenableFuture<A>, AsyncFunction<A, B>, Executor), or ExecutorService.submit(Callable) and submitAsync(AsyncCallable<A>, Executor), etc.

 

CheckedFuture

Guava 也提供了 CheckedFuture<V, X extends Exception> 接口. 一个 CheckedFuture 是一个 ListenableFuture ,包含着的方法可抛出一个检查异常。这使得我们能够更容易的创建一个 future 去执行抛出异常的逻辑。转换 ListenableFutureCheckedFuture使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>)即可。

猜你喜欢

转载自blog.csdn.net/yshuoo/article/details/83656915