谷歌guava_Google Guava –期货

谷歌guava

这篇文章是我在Google Guava上的系列文章的延续,这次涵盖了Future。 Futures类是用于使用Future / ListenableFuture接口的静态实用程序方法的集合。 Future是已提交给ExecutorService的异步任务(可运行或可调用)的句柄。 Future接口提供以下方法:获取任务的结果,检查任务是否完成或取消任务。 ListenableFuture接口扩展了Future接口,并添加了将完成侦听器设置为在任务完成后运行的功能。 要创建ListenableFuture,您首先需要装饰ExecutorService实例,如下所示:

ExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

现在,所有提交的Callables / Runnables将返回一个ListenableFuture。 MoreExecutors可以在com.google.common.util.concurrent包中找到。 ListenableFutures在覆盖以前的帖子 。 期货中有太多方法无法有效地涵盖在一篇文章中,所以我只涉及:链,转换,allAsList和successAsList。 在整个这篇文章中,我将交替使用Future和ListenableFutures。

链方法返回一个ListenableFuture,其值是通过从输入Future中获取结果并将其作为参数应用到Function对象来计算的, Function对象又返回另一个ListenableFuture。 让我们看一个代码示例并逐步执行它:

ListenableFuture<List<String>> indexSearch = 
              luceneSearcher.searchAsync('firstName:martin');

Function<List<String>, ListenableFuture<List<Person>>> queryFunction = 
 new Function<List<String>, ListenableFuture<List<Person>>>() {
            @Override
            public ListenableFuture<List<Person>> apply(final List<String> ids) {
                 return dataService.getPersonsByIdAsync(ids);
            }
        };

ListenableFuture<List<Person>> results = 
              Futures.chain(indexSearch, queryFunction,executorService);
  1. 第1行正在使用Lucene执行异步搜索,并将返回一个ID列表,这些ID代表存储在数据库中的人员记录的主键。 (我创建了一个小索引,其中存储在Lucene中的唯一数据是id的数据,其余数据仅被索引了)。
  2. 第4 – 11行正在构建功能对象,其中apply方法将使用搜索未来的结果作为输入。 从apply返回的将来是对dataService对象的调用的结果。
  3. 第12行是从链调用返回的未来。 一旦输入将来完成,将使用executorService运行该功能。

为了更加清楚,这是searchAsync和getPersonsByIdAsync方法的作用。 在前面的代码示例中,这些方法调用分别来自第2行和第8行:

public ListenableFuture<List<String>> searchAsync(final String query)  {
	        return executorService.submit(new Callable<List<String>>() {
	            @Override
	            public List<String> call() throws Exception {
	                return search(query);
	            }
	        });
  }

public ListenableFuture<List<Person>> getPersonsByIdAsync(final List<String> ids) {
        return executorService.submit(new Callable<List<Person>>() {
            @Override
            public List<Person> call() throws Exception {
                return getPersonsById(ids);
            }
        });
    }

chain方法具有两个签名:

  1. 链(ListentableFuture,函数)
  2. 链(ListenableFuture,函数,ExecutorService)

在确定使用哪种方法时,需要考虑几点。
如果通过调用时间链完成了输入将来,则所提供的函数将在调用线程中立即执行。 此外,如果未提供执行程序,则使用MoreExecutors.sameThreadExecutor。 MoreExecutors.sameThreadExecutor(顾名思义)位于ThreadPoolExecutor.CallerRunsPolicy之后,这意味着提交的任务在与执行/提交相同的线程中运行。

转变

转换方法类似于链式方法,因为它以Future和Function对象作为参数。 区别在于,不返回ListenableFuture,仅返回将给定功能应用于输入future的结果。 考虑以下:

List<String> ids = ....
ListenableFuture<List<Map<String, String>>> dbRecords =   
                                           dataService.getPersonDataByIdAsync(ids);

 Function<List<Map<String, String>>,List<Person>> transformDbResults = 
  new Function<List<String>, List<Person>>() {
              @Override
              public List<Person> apply(List<Map<String, String>> personMapList) {
                      List<Person> personObjList = new ArrayList<Person>();
                      for(Map<String,String> personDataMap : personMapList){
                             personObjList.add(new Person(personDataMap);
                      } 
                      return personObjList;
                    }
     };

ListenableFuture<List<Person>> transformedResults = 
                      Futures.transform(dbRecords, transformDbResults, executorService);
  1. 第2行执行异步数据库查找
  2. 在第4行上,正在创建一个函数对象,但是在第8行上,请注意返回类型为List <Person>

transform方法具有与chain相同的重载方法调用,但有相同的警告。

AllAsList

allAsList方法将采用任意数量的ListenableFutures作为变量或以Iterator <ListenableFuture>的形式。 返回一个ListenableFuture,其值是所有输入结果的列表。 列表中返回的值与原始列表的顺序相同。 如果任何输入值被取消或失败,则返回的ListenableFuture也将被取消或失败。 从allAsList调用取消返回的future不会传播到列表中提交的任何原始任务。

ListenableFuture<List<Person>> lf1 = getPersonsByFirstNameFuture('martin');
ListenableFuture<List<Person>> lf2 = getPersonsByFirstNameFuture('bob');
ListenableFuture<List<List<Person>>> lfResults = Futures.allAsList(lf1, lf2);
//assume lf1 failed
List<List<Person>> personLists = lfResults.get() //call results in exception


成功名单

successAsList方法与allAsList非常相似,但是更加宽容。 就像allAsList一样,successAsList返回结果列表的顺序与输入列表的顺序相同,但是如果任何输入失败或被取消,则列表中的相应值将为null。 取消返回的将来也不会取消任何原始输入。

ListenableFuture<List<Person>> lf1 = getPersonsByFirstNameFuture('martin');
ListenableFuture<List<Person>> lf2 = getPersonsByFirstNameFuture('bob');
ListenableFuture<List<List<Person>>> lfResults = Futures.successfulAsList(lf1, lf2);
//assume lf1 failed
List<List<Person>> personLists = lfResults.get();
List<Person> listOne = personLists.get(0) //listOne is null
List<Person> listTwo = personLists.get(1) //listTwo, not null


结论

希望这有助于从Google Guava发现Futures类中包含的有用性。 我创建了一个单元测试,以显示本文中描述的方法的示例用法。 由于有大量支持代码,因此我在gihub上创建了一个项目guava-blog 。 该项目还将包含我以前在Guava上的帖子( MonitorListenableFuture )中的源代码。 一如既往地欢迎提出意见和建议。

资源资源


参考资料: Google Guava –我们的JCG合作伙伴 Bill Bejeck撰写的期货,来自Random Thoughts On Coding博客。

翻译自: https://www.javacodegeeks.com/2012/11/google-guava-futures.html

谷歌guava

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值