前言:mailbox: 作者简介:小明 java 问道之路,专注于研究计算机底层,就职于金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的设计和架构:mailbox: :trophy: Java 领域优质创作者、阿里云专家博主、华为云专家:trophy::fire: 如果此文还不错的话,还请:+1: 关注 、点赞 、收藏 三连支持:+1:一下博主哦
本文导读
Java 代码为了更好的发展和性能,开发了 异步编程的模式,Future 异步编程和 CompletableFuture 接口都可以实现异步编程,我们通过源码深入理解其原理和设计的思想,Java9 中提供了反应式编程(Flow API)我们分析其源码并提供一个响应式查询实战。
一、同步与异步
1、为什么要有异步
在 Java 发展的这 20 年,他只做了一件事不被淘汰,为了不被淘汰不断的更新 jdk 的版本,以便使用计算机硬件、操作系统以及新的编程概念。
Java 一开始提供了 synchronized 锁、Runable,后面 java5 有引入了 java.util.concurrent 包,java7 中的 forkjoin 框架 java.util.concurrent.RecursiveTask,到 java8 中 Stream 流、lambda 表达式的支持,这一切都是为了支持高并发。
即便如此,多线程虽然极大的提升了性能,如果合理的使用 线程池 的话, 好处 ,第一可以降低资源消耗,重复利用已创建的线程;第二:提高响应速度,任务可以不需要等到线程创建就能立即执行;第三:提高线程的可管理性。统一分配、调优和监控。但是 线程池 也不是没有 缺点 ,使用 k 个线程的线程池就只能并发的执行 k 个任务,其他任务还是回 休眠或者阻塞 。
这时候如果有线程不和其他任务相关联,又可以不用阻塞,就好了。Java8 考虑到了,充分发挥了计算机硬件的处理能力, 异步 API 应运而生。
2、什么是同步?什么是异步?
同步就是 a 程序强依赖 b 程序,我必须等到你的回复或者执行完毕,才能做出下一步响应,类似于编程中程序被解释器(JVM)顺序执行一样(加载 > 验证 > 准备 > 解析 > 初始化);
异步则相反,a 程序不强依赖 b 程序,响应的时间也无所谓,无论你返回还是不返回,a 程序都能继续运行,也就是说我不存在等待对方的概念,a 程序就是 异步非阻塞的。
下面举一个例子就说明什么是同步、什么是异步
异步编程涉及两种风格,Future 风格 API 和反应式风格 API ,Future<Integer> fun(int a){},fun( a , x-> {}),这两个模式的实战会在后面小结讲解。
二、Future 异步编程
1、Future 接口
Java5 中就引入了 Future 接口,他的涉及初衷就是异步计算,例如我们结算一个商户下的所有订单,这个时候并不需要 for 循环去累加,Future 接口使用的时候只需要封装 Callable 中,再提交给 ExecutorService。
2、Future 接口的使用
Future 接口的使用看下 Java8 之前是如何使用异步的
public static void main(String[] args) throws Exception {
List<OrderInfo> orderInfos = Arrays.asList(new OrderInfo("123", BigDecimal.ONE),
new OrderInfo("456", BigDecimal.TEN), new OrderInfo("789", BigDecimal.TEN));
// 创建 ExecutorService 通过它可以向线程池提交任务
ExecutorService executorService = Executors.newCachedThreadPool();
// 异步操作的同时,可以进行其他操作
Future<BigDecimal> decimalFuture = executorService.submit(new Callable<BigDecimal>() {
@Override
public BigDecimal call() throws Exception {
return reduceAmt(orderInfos);
}
});
// Java8 写法
Future<BigDecimal> decimalFuture = executorService.submit(() -> reduceAmt(orderInfos));
System.out.println(decimalFuture.get());
}
private static BigDecima