Guava文档翻译之ListenableFuture
ListenableFutureExplained
并发是一个困难的问题,但是使用强大而简单的抽象可以极大地简化并发问题。为了简化事情,Guava使用ListenableFuture继承了JDK的Future接口.
我们强烈建议你在所在代码里总是使用ListenableFuture,而不是Future,因为:
- 大多数Future相关的接口需要它
- 这比以后换成ListenableFuture更容易
- 工具的提供者不需要为它们的方法分别提供Future和ListenableFuture的变体
接口 Interface
一个传统的Future代表一个异步计算的结果:一个可能已经得到结果或者还没结束的计算。一个Future可以作为一个正在进行中的计算的句柄(handle), 作为一个服务对我们的保证(promise),保证它会提供给我们一个结果。
一个ListenableFuture允许我们注册一个在计算完成时会执行的回调(callback),如果计算已经完成,就会立即执行回调。这个增加的简单功能可以让ListenableFuture支持很多基本的Future接口所不支持的操作。
ListenableFuture所增加的基本操作是addListener(Runnable, Executor), 它指明当这个Future代表的计算完成时,特定的Runnable将会在特定的Executor中执行。
填加回调 Adding Callbacks
大多数用户倾向于使用Futures.addCallback(ListenableFuture<V>, FutureCallback<V>, Executor),或者另一个默认使用MoreExecutors.sameThreadExecutor的版本,来在回调执行快速并且轻量的时候使用。一个需要实现两个方法 FutureCallback<V>:
onSuccess(V),在future成功时执行的动作,基于future的结果。onFailure(Throwable),当future失败时执行的动作,基于失败的原因。
创建 Creation
与JDK使用ExecutorService.submit(Callable)的方式来初始化一个异步的计算相类似,Guava提供了接口ListeningExecutorService,它会返回一个ListenableFuture而不像ExecutorService那样返回一个Future。如果想要把一个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的API,Guava提供了ListenableFutureTask.create(Callable<V>) 以及ListenableFutureTask.create(Runnable, V)。不像JDK,ListenableFutureTask并不是用来直接继承的。
如果你想要这样的抽象:你想直接设置future的值,而不是实现一个方法来计算这个值,考虑下继承 AbstractFuture<V> ,或者直接使用SettableFuture。
如果你必须把其它API提供的Future转成ListenableFuture,你可能别无选择,而必须使用重量级 JdkFutureAdapters.listenInPoolThread(Future)的来把一个Future转成ListenableFuture. 只要情况允许,更好的选择就是修改原来的代码,让它返回一个ListenableFuture。
应用 Application
(译注:这个application应该理解成apply的名词,是'apply a function to a value'里的apply的意思, 请从函数式编程的角度理解)
使用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.transform(rowKeyFuture, queryFunction, queryExecutor);
(译注:如果懂Scala的话,这段代码大体相当于rowKeyFuture.map(dataService.read)(queryExecutor), 要短了非常多,也更好理解。但是Scala的Future好像不像ListenableFuture可以注册多个监听器)
有很多其它的操作也可以被ListenableFuture高效的支持,但是Future就不行。不同的操作可以在不同的executor中执行,一个ListenableFuture也可以有多个等待执行的动作。
当很多个操作都要在另一个操作开始后立即执行--也就是扇出(fan-out)--ListenableFuture可以做到这点:它可以触发所有那些的需要执行的回调。多做一点工作,我们就可以扇入(fan-in),或者触发一个ListenableFuture,在其它所有的Future都完成以后,它会立即执行: 一个例子是the implementation of Futures.allAsList
| Method | Description | See also |
|---|---|---|
transform(ListenableFuture<A>, AsyncFunction<A, B>, Executor)* |
Returns a newListenableFuturewhose result is the product of applying the givenAsyncFunction to the result of the givenListenableFuture. |
transform(ListenableFuture<A>, AsyncFunction<A, B>) |
transform(ListenableFuture<A>, Function<A, B>, Executor) |
Returns a newListenableFuturewhose result is the product of applying the given Functionto the result of the givenListenableFuture. |
transform(ListenableFuture<A>, Function<A, B>) |
allAsList(Iterable<ListenableFuture<V>>) |
Returns aListenableFuturewhose 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 aListenableFuturewhose 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>...) |
| Method 方法 | Description 描述 | See also 参见 |
|---|---|---|
transform(ListenableFuture<A>, AsyncFunction<A, B>, Executor)* |
Returns a new 返回一个新的ListenableFuture, 它的结果是把给定的ListenableFuture的结果应用于给定的异步函数的结果(译注:意思是把给定的ListenableResult的result作为参数调用给定的异步函数) |
transform(ListenableFuture<A>, AsyncFunction<A, B>) |
transform(ListenableFuture<A>, Function<A, B>, Executor) |
Returns a new 返回一个新的ListenableFuture,它的结果是把给定的ListenableFuture的结果应用于给定的函数的结果 |
transform(ListenableFuture<A>, Function<A, B>) |
allAsList(Iterable<ListenableFuture<V>>) |
Returns a 返回一个新的ListenableFuture,它的结果一个list, 这个list包括了给定的一系列ListenableFuture的结果,list的元素按照这些给定的ListenableFuture的顺序。如果给定的这些futures中有任何一个被取消了或者失败了,被返回的这个ListenableFuture就会被取消或失败。 |
allAsList(ListenableFuture<V>...) |
successfulAsList(Iterable<ListenableFuture<V>>) |
Returns a 返回一个新的ListenableFuture,它的值是一个list,这个list包括了每一个成功执行的future,按照给出的顺序。跟失败或者被取消的future相关的值会被设成null |
successfulAsList(ListenableFuture<V>...) |
* An AsyncFunction<A, B> provides one method, ListenableFuture<B> apply(A input). It can be used to asynchronously transform a value.
一个提供了一个方法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);
CheckedFuture
Guava也提供了一个CheckedFuture<V, X extends Exception>接口。一个CheckedFuture 也是一个ListenableFuture,包括了各种版本的可以抛出受检异常的方法。这使得创建一个执行逻辑可能抛出异常的Future更加容易。如果想要把一个ListenableFuture转成一个CheckedFuture, 可以使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>).
总结:
ListenableFuture提供了很有价值的对JDK并发库的补充。不过同样的功能,Scala提供的Future的功能要更强大,而且Scala的语法也使得代码更简单易懂。实际上,Promise也是很强大的一种抽象,这篇Guava的文章只简单提了一下SettableFuture。想要更深入了解的可以看一下Scala的文档,这个有人翻译了,页面的右上角可以选择中文版。
Futures and Promises
Guava文档翻译之ListenableFuture的更多相关文章
- google Guava包的ListenableFuture解析
一. ListenableFuture是用来增强Future的功能的. 我们知道Future表示一个异步计算任务,当任务完成时可以得到计算结果.如果我们希望一旦计算完成就拿到结果展示给用户或者做另外 ...
- Guava并发:ListenableFuture与RateLimiter示例
ListenableFuture顾名思义就是可以监听的Future,它是对java原生Future的扩展增强 RateLimiter类似于JDK的信号量Semphore,他用来限制对资源并发访问的线程 ...
- Guava文档翻译之 Guava简介
用户指南 User Guide Guava项目包括了一些Google的核心库,是我们在基于Java的项目中所依赖的,这些库包括:集合,缓存,对基本类型的支持,并发库,通用的注解,字符串处理,I/O,等 ...
- Guava文档翻译之 Service
概览 Guava的接口代表了一个有运行状态的对象,有启动和停止的方法.比如网络服务器,RPC服务器,以及计时器等,都可以实现Service接口.掌管像这样的服务的状态,需要正确地管理启动和关闭,因此会 ...
- ListenableFuture in Guava
ListenableFuture的说明 并发编程是一个难题,但是一个强大而简单的抽象可以显著的简化并发的编写.出于这样的考虑,Guava 定义了 ListenableFuture接口并继承了JDK c ...
- Java 异步转同步 ListenableFuture in Guava
ListenableFuture的说明 并发编程是一个难题,但是一个强大而简单的抽象可以显著的简化并发的编写.出于这样的考虑,Guava 定义了 ListenableFuture接口并继承了JDK c ...
- Guava 并行 Futures实例
Future可以用来构建复杂的异步操作,方法不是返回一个值,而是一个Future对象.创建Future对象的过程(比如调用Future异步函数接口),不会阻塞当前线程操作,而且对象第一个次创建没有值, ...
- Google Guava官方教程(中文版)
Google Guava官方教程(中文版) 原文链接 译文链接 译者: 沈义扬,罗立树,何一昕,武祖 校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库, ...
- Guava 6:Concurrency
一.引子 有点经验的工程师一定对多线程比较熟悉,JDK封装的FutureTask实现了这一功能.如下图: FutureTask实现了RunnableFuture接口,而RunnableFuture接口 ...
随机推荐
- A@2a139a55 结果产生的原因
程序代码: public class ExplorationJDKSource { /** * @param args */ public static void main(String[] args ...
- Spring IOC整理
示例展示 Spring的一大特点是利用配置的xml文件实现依赖注入. 所谓依赖注入是指把一个业务对象注入另一个业务对象,从而达到对象间的松耦合.(注意是业务对象哦!)依赖注入讲的通俗一点,就是让一个对 ...
- MTD技术介绍
MTD(Memory Technology device)是用于访问memory设备(ROM.Flash)的Linux子系统,在Linux中引入这一层的主要目的是为了更加简单的添加新的Memory存储 ...
- 《squid网卡代理的实现》RHEL6.3——条理清晰,步骤明确
网卡的代理和FQ差不多一个道理.ping 不通不代表不能上网. 实验的目的: 打开2台虚拟主机,一台2个网卡(这台为服务器):一台一个网卡: 2块网卡的服务器使用静态ip可以上网,也就是说网段为1的可 ...
- js设计模式(8)---享元模式
0.前言 今天总结了四种设计模式,到现在有点精疲力尽了,但是还是有不少收获,很开心自己有掌握了新的东西,今天变得有了价值. 1.使用条件 1.1.网页中使用了大量资源密集型的对象: 1.2.这些对象中 ...
- C# 解析XML格式的字符串
public CreateOrderReturnResult GetCreateOrderReturnApi() { var result = new CreateOrderReturnResult( ...
- 转:const“变量”、define的常量和static 变量
首先讲C编译器的内存分配: 代码区 数据区 用户区=线程栈+堆 其中的数据区存储:常量(define)+静态变量(static)+符号集(const)+全局变量 然后讲一下编译的大致顺序: 注释- ...
- 浅析php fwrite写入txt文件的时候用 \r\n不能换行的问题
以下是对php中fwrite写入txt文件的时候用 \r\n不能换行的问题进行了介绍,需要的朋友可以过来参考下今天遇到了一个问题就是用fwrite写入txt文件的时候用 rn不能换行试了很久都没找到办 ...
- [转]PHP中fopen,file_get_contents,curl的区别
1. fopen /file_get_contents 每次请求都会重新做DNS查询,并不对 DNS信息进行缓存.但是CURL会自动对DNS信息进行缓存.对同一域名下的网页或者图片的请求只 ...
- Mysql 正则获取字段的交集【转】
问题描述 比如table1中有两条记录 name no a 2,9 b 8,10 然后有一串字符串,是0,1,2,3,4 然后通过一条sql,找出no为2,9的记录来``` 因为字符串中有 ...