并发是一个难题,但是可以通过使用强力简单的抽象来显著的简化,为了简化问题,guava扩展了Future接口,即 ListenableFuture (可以监听的Future)。

我强烈建议你在你的所有代码里使用ListenableFuture去替代Future,原因如下:

很多的Futures 类的方法需要它。(Futures工具类使用)

它比后来改造为ListenableFutrue更简单。(早点使用比重构更简单)

工具方法的提供者不需要提供Future和ListenableFuture方法的变体。(不需要兼容两套)

接口

一个传统的Futrue代表一个异步计算的结果:一个可能完成也可能没有完成输出结果的计算。

一个Future可以用在进度计算,或者说是 一个提供给我们结果的服务的承诺。

一个ListenableFuture允许注册当你在计算完成的时候的回调,或者计算已经完成了。

这个简单的增强让高效支持多种操作成为可能。而Future接口并不能支持。

ListenbleFuture中添加的基本操作是

addListener(Runnable , Executor ),

它指出了当未来计算完成时,指定的Runnable会在指定的Executor中运行。

增加回调

很多用户喜欢使用 Futures.addCallback(ListenableFuture,FutureCallback,Executor)方法。

FutureCallback实现了下面两个方法:

onSuccess(v) 当未来成功执行的动作,基于计算结果

onFailure(Throwable) 当未来失败执行的动作,基于失败

创建

相较于jdk提供的 ExecutorService.submit(Callable)方法来初始化一个异步计算。它返回一个常规的Future,

guava提供了ListeningExecutorService接口,它返回ListenableFuture。

把ExecutorService转换为ListenableExecutorService

使用:MoreExecutors.listeningDecorator(ExecutorService)

基础用法如下:

/**

* 说明:使用例子代码

* @author carter

* 创建时间: 2020年03月19日 9:54 上午

**/

@Slf4j

public class ListenableFutureUtils {

public static void main(String[] args) {

ListeningExecutorService service = MoreExecutors.listeningDecorator(

Executors.newFixedThreadPool(10));

final ListenableFuture listenableFuture = service.submit(() -> {

try {

TimeUnit.SECONDS.sleep(5);

} catch (InterruptedException e) {

e.printStackTrace();

}

return new AResult(30, "male", 1);

});

Futures.addCallback(listenableFuture,

new FutureCallback() {

@Override

public void onSuccess(AResult aResult) {

log.info("计算成功,{}",aResult);

}

@Override

public void onFailure(Throwable throwable) {

log.error("计算错误",throwable);

}

},service);

}

@Data

@AllArgsConstructor

public static class AResult{

private Integer age;

private String sex;

private Integer id;

}

}

相对的,如果你想从基于FutureTask的API转换过来,

Guava提供了

ListenableFutureTask.create(Callable)

ListenableFutureTask.create(Runnable)

不同于jdk,ListenableFutureTask并不是直接扩展的。

如果你喜欢抽象的设置future的值,而不是实现一个方法然后计算值,可以考虑使用AbstractFuture或使用SettableFuture ;

如果你必须转换Future为ListenableFuture,你别无选择,必须使用 JdkFutureAdapters.listenInPoolThread(Future)来转换Future为ListenableFuture

任何时候只要可能,推荐你修改源码让它返回一个 ListenableFuture

应用

使用ListenablFuture最重要的原因是可以使用链式异步操作。

代码如下:

package com.xxx.demo;

import com.google.common.util.concurrent.AsyncFunction;

import com.google.common.util.concurrent.Futures;

import com.google.common.util.concurrent.ListenableFuture;

import lombok.AllArgsConstructor;

import lombok.Data;

/**

* 说明:异步操作链

* @author carter

* 创建时间: 2020年03月19日 10:11 上午

**/

public class ApplicationUtils {

public static void main(String[] args) {

Query query = new Query(30);

ListenableFuture rowKeyFuture = lookUp(query);

AsyncFunction queryFun = rowKey -> readData(rowKey);

final ListenableFuture queryResultListenableFuture =

Futures.transformAsync(rowKeyFuture, queryFun);

}

private static ListenableFuture readData(RowKey rowKey) {

return null;

}

private static ListenableFuture lookUp(Query query) {

return null;

}

@Data

@AllArgsConstructor

public static class RowKey {

private String id;

}

@Data

@AllArgsConstructor

public static class Query {

private Integer age;

}

@Data

@AllArgsConstructor

public static class QueryResult {

private String id;

private String age;

}

}

很多其他高效支持的操作ListenableFuture提供,而Future不提供。

不同的操作可以被不同的线程池执行,一个简单的ListenableFuture可以有多个操作去等待。

只要一个操作开始,其他多个操作应该开始,fan-out, 千帆竞发。

ListenableFuture可以实现这样的操作:它触发了所有请求的回调。

通过少量的工作,我们可以 fan-in.

触发一个ListenableFuture 来获得计算结果,当其他的Future结束的时候。

Futures.allAsList是一个例子。

方法介绍:

方法

描述

transformAsync(ListenableFuture , AsyncFunction , Executor)

返回一个新的ListenableFuture,它的结果是执行异步函数的返回,函数入参是ListenableFuture的返回结果;

transform(ListenableFuture , Function , Executor)

返回一个新的ListenableFuture,它的结果是执行函数的返回,函数入参是ListenableFuture的返回结果;

allAsList(Iterable

)

返回一个ListenableFuture,它的结果是一个list,包含每一个列表中的ListenableFuture的执行结果,任何一个ListenableFuture执行失败或者取消,最后的返回结果取消

successfullAsList(Iterable

)

返回一个ListenableFuture,它的结果是一个list,包含每一个列表中的ListenableFuture的执行结果,成功的是结果,失败或者取消的值使用null替代

AsyncFunction 提供了一个方法 , ListenableFutureapply(A inpunt),它可以用来异步的转换值。

代码如下: package com.xxx.demo;

import com.google.common.collect.Lists;

import com.google.common.util.concurrent.FutureCallback;

import com.google.common.util.concurrent.Futures;

import com.google.common.util.concurrent.ListenableFuture;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**

* 说明:成功执行结果汇集

* @author carter

* 创建时间: 2020年03月19日 10:34 上午

**/

@Slf4j

public class Test3 {

public static void main(String[] args) {

List> querys = Lists.newLinkedList();

final ListenableFuture> successfulAsList =

Futures.successfulAsList(querys);

Futures.addCallback(successfulAsList, new FutureCallback>() {

@Override

public void onSuccess(List queryResults) {

log.info("执行结果列表:{}",queryResults);

}

@Override

public void onFailure(Throwable throwable) {

log.error("执行失败",throwable);

}

});

}

@Data

@AllArgsConstructor

public static class QueryResult{

private Integer age;

}

}

嵌套的Future

你的代码调用一个通用接口并返回一个Future,很可能最终返回一个嵌套的Future. package com.xxx.demo;

import com.google.common.util.concurrent.ListenableFuture;

import com.google.common.util.concurrent.ListeningExecutorService;

import com.google.common.util.concurrent.MoreExecutors;

import lombok.AllArgsConstructor;

import lombok.Data;

import java.util.concurrent.Callable;

import java.util.concurrent.Executors;

/**

* 说明:嵌套的ListenableFuture

* @author carter

* 创建时间: 2020年03月19日 10:43 上午

**/

public class Test4 {

public static void main(String[] args) {

final ListeningExecutorService executorService = MoreExecutors

.listeningDecorator(Executors.newFixedThreadPool(2));

final ListeningExecutorService otherExecutorService = MoreExecutors

.listeningDecorator(Executors.newFixedThreadPool(2));

Callable otherCallback = ()->new Foo("aaa");

final ListenableFuture> submit =

executorService.submit(() -> otherExecutorService.submit(otherCallback));

}

@Data

@AllArgsConstructor

public static class Foo{

private String name;

}

}

例子最后返回的是: ListenableFuture

> ,

这个代码不对,因为当外层的Future 取消的时候,无法传播到内层的Future,

这也是一个 使用get()检查别的Future或者Listnener的常规的错误,

但是,除非特别关注 否则 otherCallback抛出的异常会被压制。

为了避免这种情况,所有的guava的Future处理方法(有些从jdk来),有 *Async版本来安全的解开这个嵌套。

比如:transform,transformAsyn, submit, submitAsync方法。

深入研究

原创不易,转载请注明出处。

java并发增强工具_0318 guava并发工具相关推荐

  1. JAVA线程并发数量控制_线程同步工具(二)控制并发访问多个资源

    声明:本文是< Java 7 Concurrency Cookbook>的第三章, 作者: Javier Fernández González 译者:郑玉婷 控制并发访问多个资源 在并发访 ...

  2. java工具谷歌工具-Google guava工具类的介绍和使用

    工具类 就是封装平常用的方法,不需要你重复造轮子,节省开发人员时间,提高工作效率.谷歌作为大公司,当然会从日常的工作中提取中很多高效率的方法出来.所以就诞生了guava. guava的优点: 高效设计 ...

  3. Java工具库Guava的区间(范围Range)的构建、区间运算、查询运算、关系运算(包含、相连、交集、并集)的使用示例

    场景 Java核心工具库Guava介绍以及Optional和Preconditions使用进行非空和数据校验: Java核心工具库Guava介绍以及Optional和Preconditions使用进行 ...

  4. 基准测试工具(压测工具):wrk---高并发、损耗低,安装简单 (一)

    基准测试工具:Wrk初识   最近和同事聊起常用的一些压测工具,谈到了Apache ab.阿里云的PTS.Jmeter.Locust以及wrk各自的一些优缺点和适用的场景类型. 这篇博客,简单介绍下H ...

  5. java并发多线程面试_Java多线程并发面试问答

    java并发多线程面试 Today we will go through Java Multithreading Interview Questions and Answers. We will al ...

  6. Java:计算机编程语言Java的简介、安装(编程环境/工具)、学习路线(如何学习Java以及几十项代码编程案例分析)之详细攻略

    Java:计算机编程语言Java的简介.安装(编程环境/工具).学习路线(如何学习Java以及几十项代码编程案例分析)之详细攻略 目录 Java的简介 1.Java的工作原理--基于Eclipse等编 ...

  7. Fork and Join: Java也可以轻松地编写并发程序 原文地址 作者:Julien Ponge 译者:iDestiny 资源下载: Java SE 7 Sample Code(Zi

    Fork and Join: Java也可以轻松地编写并发程序 原文地址   作者:Julien Ponge 译者:iDestiny 资源下载: Java SE 7 Sample Code(Zip) ...

  8. Java 面试知识点解析(二)——高并发编程篇

    前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...

  9. 《深入理解Java虚拟机》笔记6——高效并发

    第五部分 高效并发 第十二章 Java内存模型与线程 并发处理的广泛应用是使得Amdahl定律代替摩尔定律成为计算机性能发展源动力的根本原因,也是人类"压榨"计算机运算能力的最有力 ...

  10. Java 8系列之Stream的强大工具Collector

    Stream系列: Java 8系列之Stream的基本语法详解 Java 8系列之Stream的强大工具Collector Java 8系列之重构和定制收集器 Java 8系列之Stream中万能的 ...

最新文章

  1. Codeforces Round #144 (Div. 2) B. Non-square Equation 数学解一元二次方程+分析
  2. SAP CRM One Order函数CRM_Object_FILL_OW的设计原理
  3. 数学建模学习笔记(十二)——奇异值分解
  4. 怎么保存python文件_python如何保存文本文件
  5. T-SQL: 读取磁盘文件
  6. JVM 字节码指令手册 - 查看 Java 字节码
  7. android dts播放器下载,安卓dts音效apk安装包
  8. 软件开发:关于园林绿化工中级理论知识题题库的软件内容
  9. 福田中心区20个楼盘航拍全景
  10. 本人累计多年整理的所有软件 需要请留言 适合毕业设计参考
  11. 贵州国际商品交易中心依托实体经济发展虚拟经济
  12. 无线网络 开启nat共享服务器,wifi共享大师开启NAT服务出错的解决方案
  13. webRTC(十一):webrtc 实时共享桌面
  14. 数据库 day60,61 Oracle入门,单行函数,多表查询,子查询,事物处理,约束,rownum分页,视图,序列,索引
  15. 浏览器输入www.baidu.com之后,发生了什么?
  16. 各种靠谱教程总结(后续更新)
  17. dbd mysql db_mysqlhotcopy备份时出现“DBD::mysql::db do faile\问题-huifeideluotuo-ChinaUnix博客...
  18. 力扣860题 柠檬水找零 Java版
  19. Element UI 改变主题色
  20. reCAPTCHA v3 验证

热门文章

  1. arcgis怎么压缩tif文件_PDF文件怎么压缩?两招帮你解决PDF压缩难题!
  2. MATLAB与word的交互
  3. CAN FD的波特率到底能跑多快?
  4. HTTP利用API接口,解密生意参谋
  5. dqo变换_基于dqO变换的电压暂降检测方法研究
  6. 服务器怎么开启lldp协议,修改服务器lldp的mac地址
  7. sql列转行逗号连接_SQL 拼接字符串 列转行 | 学步园
  8. html界面设计用什么软件,html网页开发常用软件有哪些
  9. 蜗牛星际改内存_蜗牛星际再次升级为800多元的变种蜗牛:G5400+B365的双千兆网口做NAS香吗...
  10. 据说200G网盘资料