Java 8原生API也可以开发响应式代码?

前段时间工作上比较忙,这篇文章一直没来得及写,本文是阅读《Java8实战》的时候,了解到Java 8里已经提供了一个异步非阻塞的接口(CompletableFuture),可以实现简单的响应式编程的模式,因此用这篇文章做个梳理。我是带着下面这几个问题去学习CompletableFuture这个接口的,
- CompletableFuture是为了解决什么问题而设计的?
- 它的使用场景是什么?开源软件中有实战使用案例吗?
- CompletableFuture的常用API都有哪些?如何使用?
- CompletableFuture和RxJava有什么不同?
这篇文章梳理下来,基本上可以回答前面四个问题,OK,我们进入正文。
基本概念

RPC(远程方法调用)的四种方式有:oneway、sync、future和callback,在dubbo或bolt这类通信框架中,默认使用的是sync模式(同步+阻塞),future和callback都属于异步模式,不过future模式在get的时候会阻塞,callback模式则不需要等待结果,有结果后服务端会回调请求方。
异步调用这类模式,比较适合的场景是IO密集型场景,要执行很多远程调用的任务,并且这些调用耗时可能比较久。以openwrite中的一个case为例:我发布一篇文章,需要给几个不同的写作平台创建文章,这时候我不希望这个过程是顺序的,就比较适合用异步调用模式。
Future模式除了在get()调用的时候会阻塞外,还有其他的局限性,例如:没有使用Java Lambda表达式的优势,对一连串的异步调用可以支持,但是写出来的代码会比较复杂。
CompletableFuture的常用API
阅读CompletableFuture的API的时候,我有一个体会——CompletableFuture之于Future,除了增加了回调这个最重要的特性,其他的特性有点像Stream对于集合迭代的增强。
使用CompletableFuture,我们可以像Stream一样使用一部调用,可以处理一些级联的异步调用(类似于Stream里的flatMap)、可以过滤一些无用的异步调用(anyOf、allOf)。
下面这张图是我按照自己的理解,梳理除了CompletableFuture常见的API,阅读的时候需要注意下面几个点:
- 把握几个大的分类:创建CompletableFuture、获取CompletableFuture的执行结果、主动结束CompletableFuture、异步调用任务的组合处理;
- 看着方法多,但是有规律可循,例如apply字样的接口,传入的方法参数都是有返回值的;
- 带either字样的,都是多个异步任务有一个满足条件即可的;
- 带executor方法的,都表示该方法可以用自定义的线程池来优化性能。

Dubbo项目中的使用案例
Dubbo对于异步化的支持起始在2.6.x中就有提供,是在发布bean的时候加个属性配置——async=true,然后利用上下文将异步标识一层层传递下去。在之前的公司中有一次排查dubbo(当时我们用的是dubbox)异步调用的问题,最后查到的原因就是多个异步调用,上下文里的信息串了。
Dubbo 2.7 中使用了 JDK1.8 提供的 CompletableFuture 原生接口对自身的异步化做了改进。CompletableFuture 可以支持 future 和 callback 两种调用方式。在Dubbo最新的master代码中,我知道了Dubbo的异步结果的定义,它的类图如下,可以看出AsyncRpcResult是一个CompletableFuture接口的实现。

实战Demo
通过下面的例子,可以看出CompletableFuture的最大好处——callback特性。首先定义一个接口,其中包括同步接口和该接口的异步版本。
public interface AsyncInterfaceExample {
String computeSomeThine();
CompletableFuture<String> computeSomeThingAsync();
}
然后定义该接口的实现类,可以看出,如果要讲现有的同步接口异步化,是比较容易的;
public class AsyncInterfaceExampleImpl implements AsyncInterfaceExample {
@Override
public String computeSomeThine() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "hello, world";
}
@Override
public CompletableFuture<String> computeSomeThingAsync() {
return CompletableFuture.supplyAsync(this::computeSomeThine);
}
}
然后看下我们的测试case,如下:
public class AsyncInterfaceExampleTest {
private static String getOtherThing() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "other";
}
public static void main(String[] args) {
AsyncInterfaceExample asyncInterfaceExample = new AsyncInterfaceExampleImpl();
//case1 同步调用
long start = System.currentTimeMillis();
String someThing = asyncInterfaceExample.computeSomeThine();
String other = getOtherThing();
System.out.println("cost:" + (System.currentTimeMillis() - start) + " result:" + someThing + other);
//case2 异步调用,使用回调
start = System.currentTimeMillis();
CompletableFuture<String> someThingFuture = asyncInterfaceExample.computeSomeThingAsync();
other = getOtherThing();
long finalStart = start;
String finalOther = other;
someThingFuture.whenComplete((returnValue, exception) -> {
if (exception == null) {
System.out.println(
"cost:" + (System.currentTimeMillis() - finalStart) + " result:" + returnValue + finalOther);
} else {
exception.printStackTrace();
}
});
}
}
上面这个案例的执行结果如下图所示:
***
本号(javaadu)专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。
Java 8原生API也可以开发响应式代码?的更多相关文章
- Android Java使用JavaMail API发送和接收邮件的代码示例
JavaMail是Oracle甲骨文开发的Java邮件类API,支持多种邮件协议,这里我们就来看一下Java使用JavaMail API发送和接收邮件的代码示例 使用Javamail发送邮件,必需的j ...
- Windows10 UWP开发 - 响应式设计
Windows10 UWP开发 - 响应式设计 本篇随笔与大家简单讨论一下在开发适配不同分辨率.宽高比的Windows10 Universal App布局时的可行方式与小技巧.经验均从实践中总结, ...
- 使用Bootstrap 3开发响应式网站实践07,页脚
页脚部分比较简单,把一个12列的Grid切分. <footer> <div class="container"> <div class="r ...
- 使用Bootstrap 3开发响应式网站实践06,使用ListGroup、Thumbnails展示内容
□ ListGroup展示内容 当希望把同类型的内容以列表.区块展示的时候,ListGroup是不错的选择. <div class="col-sm-6"> <h3 ...
- 使用Bootstrap 3开发响应式网站实践05,使用Tab、Modal、Form展示内容,使用Popover、Tooltip展示提示信息
本篇体验用Tab插件显示内容.Html部分为: <div class="row" id="moreInfo"> <div class=&quo ...
- 使用Bootstrap 3开发响应式网站实践04,使用Panels展示内容
在Bootstrap页面中,通常用Panels来展示主要功能的内容.该部分Html为: <div class="row" id="featureHeading&qu ...
- 使用Bootstrap 3开发响应式网站实践03,轮播下方的内容排版
通常把一些重要信息.需要重点标注的信息放在轮播的下方显示,这部分区域用到了大字体的标题.副标题以及段落文字等. <div class="row" id="bigCa ...
- 使用Bootstrap 3开发响应式网站实践02,轮播
本篇体验图片轮播.html部分为: <div class="carousel slide" id="myCarousel" > <!--Ind ...
- 使用Bootstrap 3开发响应式网站实践01,前期准备、导航区域等
"使用Bootstrap 3开发响应式网站实践"系列,将使用Bootstrap 3.2制作一个自适应网站,无论是在电脑.平板,还是手机上,都呈现比较好的效果.在电脑浏览器上的最终效 ...
随机推荐
- 存储账户静态网站与Azure CDN
背景 把静态网站或文件托管在对象存储上,有很多可能很多好处,比如说:可以节省成本,因为相对虚机更便宜:性能更优,因为可以依赖于对象存储本身的高吞吐以及 CDN 的:更好的高可用性,因为也可以依赖于对象 ...
- 花5分钟时间来了解一下高性能网关Kong会有意外收获
前言 前几天开源发布了 Kong.Net 项目,收到了大量园友的反馈,开源当天就突破了 100 个star ,可喜可贺,但是从侧面也说明,我们 .NetCore 阵营真的非常需要拥抱开源,应该敞开心扉 ...
- 深入学习Spring框架(一)- 入门
1.Spring是什么? Spring是一个JavaEE轻量级的一站式开发框架. JavaEE: 就是用于开发B/S的程序.(企业级) 轻量级:使用最少代码启动框架,然后根据你的需求选择,选择你喜欢的 ...
- git报错---If no other git process is currently running...
今天帮同事上传一个代码(预生产环境),当我执行到git add 文件 的时候,出现了如下错误: If no other git process is currently running, this p ...
- asp.net core 系列之Configuration
在ASP.NET Core中的App configuration 是通过configuration providers基于key-value对建立的.Configuration providers读取 ...
- flink window实例分析
window是处理数据的核心.按需选择你需要的窗口类型后,它会将传入的原始数据流切分成多个buckets,所有计算都在window中进行. flink本身提供的实例程序TopSpeedWindowin ...
- SpringCloud解析之Zuul(一)
本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解.如有不对的地方,欢迎指正. spring bo ...
- 百度小程序自定义通用toast组件
百度小程序Toast组件 author: @TiffanysBear 百度小程序自定义通用toast组件 BdToast百度小程序自定义通用组件-github地址 需求 手百小程序的toast仅支持在 ...
- 小代学Spring Boot之集成MyBatis
想要获取更多文章可以访问我的博客 - 代码无止境. 上一篇小代同学在Spring Boot项目中配置了数据源,但是通常来讲我们访问数据库都会通过一个ORM框架,很少会直接使用JDBC来执行数据库操作的 ...
- (CVE-2017-10271)weblogic12.1.3.0漏洞测试与打补丁过程
1.漏洞测试 搭建完成weblogic12.1.3.0后,开始用工具测试 点击connect,右下角显示connected,说明已连接→说明漏洞存在 CMD输入:ls ,然后点击Execute执行 ...