并发是一个很难的问题,但是通过使用强大的和简单的抽象,它被大大简化了。方便起见, Guava 继承了JDK的 Future
接口 实现了 ListenableFuture
.
我们强烈建议在代码中总是使用 ListenableFuture
代替 Future
, 因为:
大部分的 Futures
方法都需要它.ListenableFuture
更容易.Future
与 istenableFuture
的变体在方法中.一个传统的 Future
表示异步计算的结果: 这可能是一个完成或尚未完成的计算结果。 Future
可以是正在进行的计算的程序的承诺在将来提供我们结果。
ListenableFuture
允许去注册回调在计算完成后执行,或者计算已经完成就立即执行。这种简单的添加使得有可能有效地支持基本的Future
接口无法支持的许多操作。
ListenableFuture
的基础添加操作是 addListener(Runnable, Executor)
, 当指定的Future
计算完成,特殊的Runnable
将运行在指定的Executor上
。
大多数人更愿意使用 Futures.addCallback(ListenableFuture
, 或者当返回非常快且重要时使用版本默认的 MoreExecutors.directExecutor()
。 FutureCallback
实现了两个方法:
onSuccess(V)
, 如果执行成功,根据其结果执行。onFailure(Throwable)
,如果执行失败,根据其结果执行。对应于 JDK的初始化一步计算的方法 ExecutorService.submit(Callable)
, Guava 提供了 ListeningExecutorService
接口, 它将在ExecutorService返回一个正常
Future的任何地方返回一个
ListenableFuture
. 将 ExecutorService
转换为ListeningExecutorService
, 可以使用 MoreExecutors.listeningDecorator(ExecutorService)
.
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)); ListenableFuture explosion = service.submit(new Callable() {
public Explosion call() {
return pushBigRedButton();
}
});
Futures.addCallback(explosion, new FutureCallback() {
// 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
与 ListenableFutureTask.create(Runnable, V)
. 不像 JDK, ListenableFutureTask
不意味着直接继承。
如果你喜欢一个抽象,在其中你设置future 的价值而不是实现一个方法来计算这个值,,考虑继承AbstractFuture
或者直接使用SettableFuture
.
如果必须从其他的API将 Future
转换为 ListenableFuture
, 只能选择JdkFutureAdapters.listenInPoolThread(Future)
最好修改源代码返回 ListenableFuture
.
使用 ListenableFuture
最重要的原因是其提供了复杂的异步操作链。
ListenableFuture rowKeyFuture = indexService.lookUp(query);
AsyncFunction queryFunction = new AsyncFunction() {
public ListenableFuture apply(RowKey rowKey) {
return dataService.read(rowKey);
}
};
ListenableFuture queryFuture = Futures.transformAsync(rowKeyFuture, queryFunction, queryExecutor);
许多其他的操作可以有效地支持 ListenableFuture
不能单独的支持 Future
.不同的操作可以由不同的执行器执行,单个ListenableFuture可以有多个操作等待执行。
Method | Description | See also |
---|---|---|
transformAsync(ListenableFuture, AsyncFunction, Executor) * |
Returns a new ListenableFuture whose result is the product of applying the given AsyncFunction to the result of the given ListenableFuture . |
transformAsync(ListenableFuture, AsyncFunction) |
transform(ListenableFuture, Function, Executor) |
Returns a new ListenableFuture whose result is the product of applying the given Function to the result of the given ListenableFuture . |
transform(ListenableFuture, Function) |
allAsList(Iterable |
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 |
successfulAsList(Iterable |
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 |
*
一个 AsyncFunction
提供一个方法, ListenableFuture apply(A input)
. 其可以被用来异步的转换一个值。
List> queries;
// The queries go to all different data centers, but we want to wait until they're all done or failed.
ListenableFuture> successfulQueries = Futures.successfulAsList(queries);
Futures.addCallback(successfulQueries, callbackOnSuccessfulQueries);
在例子中代码访问了传统的接口以及返回一个 Future, 可能结束语嵌套的 Future
s. 例如:
executorService.submit(new Callable() {
@Override
public ListenableFuture call() {
return otherExecutorService.submit(otherCallable);
}
});
将返回 ListenableFuture
. 这个代码不正确, 因为如果一个 cancel
在输出的路径,并完成在 外部的 future, 那么取消将不会传播进 future中。代码也犯了一个经常犯的错,检查失败使用其他future的get()或监听器。至少应该关心的是从otherCallable
抛出的异常将被抑制。为了避免上面的情况, 所有的 Guava future-handling 方法 (一些来自 JDK) 都有 *Async 版本安全的打开异常嵌套 - transform(ListenableFuture, Function, Executor)
and transformAsync(ListenableFuture, AsyncFunction, Executor)
, or ExecutorService.submit(Callable)
and submitAsync(AsyncCallable, Executor)
, etc.
Guava 也提供了 CheckedFuture
接口. 一个 CheckedFuture
是一个 ListenableFuture
,包含着的方法可抛出一个检查异常。这使得我们能够更容易的创建一个 future 去执行抛出异常的逻辑。转换 ListenableFuture
为CheckedFuture
, 使用
Futures.makeChecked(ListenableFuture
即可。