一、CompletableFuture 简介

  

CompletableFuture 在 Java 里面被用于异步编程,异步通常意味着非阻塞,可以使得我们的任务单独运行在与主线程分离的其他线程中,并且通过回调可以在主线程中得到异步任务的执行状态,是否完成,和是否异常等信息。

CompletableFuture 实现了 Future, CompletionStage 接口,实现了 Future 接口就可以兼容现在有线程池框架,而 CompletionStage 接口才是异步编程的接口抽象,里面定义多种异步方法,通过这两者集合,从而打造出了强大的CompletableFuture 类。

二、Future 与 CompletableFuture

  Futrue 在 Java 里面,通常用来表示一个异步任务的引用,比如我们将任务提交到线程池里面,然后我们会得到一个 Futrue,在 Future 里面有 isDone 方法来 判断任务是否处理结束,还有 get 方法可以一直阻塞直到任务结束然后获取结果,但整体来说这种方式,还是同步的,因为需要客户端不断阻塞等待或者不断轮询才能知道任务是否完成。

  Future 的主要缺点如下:

  (1)不支持手动完成

    我提交了一个任务,但是执行太慢了,我通过其他路径已经获取到了任务结果,现在没法把这个任务结果通知到正在执行的线程,所以必须主动取消或者一直
等待它执行完成。

  (2)不支持进一步的非阻塞调用

    通过 Future 的 get 方法会一直阻塞到任务完成,但是想在获取任务之后执行额外的任务,因为 Future 不支持回调函数,所以无法实现这个功能

  (3)不支持链式调用

    对于 Future 的执行结果,我们想继续传到下一个 Future 处理使用,从而形成一个链式的 pipline 调用,这在 Future 中是没法实现的

  (4)不支持多个 Future 合并

    比如我们有 10 个 Future 并行执行,我们想在所有的 Future 运行完毕之后,执行某些函数,是没法通过 Future 实现的

  (5)不支持异常处理

    Future 的 API 没有任何的异常处理的 api,所以在异步运行时,如果出了问题是不好定位的

三、CompletableFuture 入门

1、使用 CompletableFuture

  场景:主线程里面创建一个 CompletableFuture,然后主线程调用 get 方法会阻塞,最后我们在一个子线程中使其终止。

    /*** 主线程里面创建一个 CompletableFuture,然后主线程调用 get 方法会阻塞,最后我们在一个子线程中使其终止* @param args*/public static void main(String[] args) throws Exception{CompletableFuture<String> future = new CompletableFuture<>();new Thread(() -> {try{System.out.println(Thread.currentThread().getName() + "子线程开始干活");//子线程睡 5 秒Thread.sleep(5000);//在子线程中完成主线程future.complete("success");}catch (Exception e){e.printStackTrace();}}, "A").start();//主线程调用 get 方法阻塞System.out.println("主线程调用 get 方法获取结果为: " + future.get());System.out.println("主线程完成,阻塞结束!!!!!!");}

2、没有返回值的异步任务

public class CompletableFutureDemo {public static void main(String[] args) throws Exception {System.out.println("主线程开始");//运行一个没有返回值的异步任务CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(()->{try {System.out.println("子线程启动干活");System.out.println(Thread.currentThread().getName()+" : CompletableFuture1");Thread.sleep(5000);System.out.println("子线程完成");} catch (Exception e) {e.printStackTrace();}});//主线程阻塞completableFuture1.get();System.out.println("主线程结束");}
}

3、有返回值的异步任务

public class CompletableFutureDemo2 {public static void main(String[] args) throws ExecutionException, InterruptedException {System.out.println("主线程开始");//运行一个有返回值的异步任务CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{try {System.out.println("子线程开始任务");System.out.println(Thread.currentThread().getName()+" : CompletableFuture2");Thread.sleep(5000);//模拟异常int i = 10/0;} catch (Exception e) {e.printStackTrace();}return 1024;});completableFuture2.whenComplete((t,u)->{System.out.println("------t="+t);  //返回值信息System.out.println("------u="+u);  //方法中的异常信息}).get();//主线程阻塞Integer s = completableFuture2.get();System.out.println("主线程结束, 子线程的结果为:" + s);}
}

4、线程依赖

  当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。

    private static Integer num = 10;/*** 先对一个数加 10,然后取平方* @param args*/public static void main(String[] args) throws Exception{System.out.println("主线程开始");CompletableFuture<Integer> future =CompletableFuture.supplyAsync(() -> {try {System.out.println("加 10 任务开始");num += 10;} catch (Exception e) {e.printStackTrace();}return num;}).thenApply(integer -> {return num * num;});Integer integer = future.get();System.out.println("主线程结束, 子线程的结果为:" + integer);}

5、消费处理结果

  thenAccept 消费处理结果, 接收任务的处理结果,并消费处理,无返回结果。

    private static Integer num = 10;public static void main(String[] args) throws Exception{System.out.println("主线程开始");CompletableFuture.supplyAsync(() -> {try {System.out.println("加 10 任务开始");num += 10;} catch (Exception e) {e.printStackTrace();} return num;}).thenApply(integer -> {return num * num;}).thenAccept(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) {System.out.println("子线程全部处理完成,最后调用了 accept,结果为:" +integer);}});}

6、异常处理

  exceptionally 异常处理,出现异常时触发

    private static Integer num = 10;public static void main(String[] args) throws Exception{System.out.println("主线程开始");CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {int i= 1/0;System.out.println("加 10 任务开始");num += 10;return num;}).exceptionally(ex -> {System.out.println(ex.getMessage());return -1;});System.out.println(future.get());}

  handle 类似于 thenAccept/thenRun 方法,是最后一步的处理调用,但是同时可以处理异常

    private static Integer num = 10;public static void main(String[] args) throws Exception{System.out.println("主线程开始");CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {System.out.println("加 10 任务开始");num += 10;return num;}).handle((i,ex) ->{System.out.println("进入 handle 方法");if(ex != null){System.out.println("发生了异常,内容为:" + ex.getMessage());return -1;}else{System.out.println("正常完成,内容为: " + i);return i;}});System.out.println(future.get());}

7、结果合并

  thenCompose 合并两个有依赖关系的 CompletableFutures 的执行结果

    private static Integer num = 10;public static void main(String[] args) throws Exception{System.out.println("主线程开始");//第一步加 10CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {System.out.println("加 10 任务开始");num += 10;return num;});//合并CompletableFuture<Integer> future1 = future.thenCompose(i ->//再来一个 CompletableFutureCompletableFuture.supplyAsync(() -> {return i + 1;}));System.out.println(future.get());System.out.println(future1.get());}

  thenCombine 合并两个没有依赖关系的 CompletableFutures 任务

    private static Integer num = 10;public static void main(String[] args) throws Exception{System.out.println("主线程开始");CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {System.out.println("加 10 任务开始");num += 10;return num;});CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {System.out.println("乘以 10 任务开始");num = num * 10;return num;});//合并两个结果CompletableFuture<Object> future = job1.thenCombine(job2, newBiFunction<Integer, Integer, List<Integer>>() {@Overridepublic List<Integer> apply(Integer a, Integer b) {List<Integer> list = new ArrayList<>();list.add(a);list.add(b);return list;}});System.out.println("合并结果为:" + future.get());}

  合并多个任务的结果 allOf 与 anyOf  allOf: 一系列独立的 future 任务,等其所有的任务执行完后做一些事情

    private static Integer num = 10;/*** 先对一个数加 10,然后取平方* @param args*/public static void main(String[] args) throws Exception{System.out.println("主线程开始");List<CompletableFuture> list = new ArrayList<>();CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {System.out.println("加 10 任务开始");num += 10;return num;});list.add(job1);CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {System.out.println("乘以 10 任务开始");num = num * 10;return num;});list.add(job2);CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {System.out.println("减以 10 任务开始");num = num * 10;return num;});list.add(job3);CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {System.out.println("除以 10 任务开始");num = num * 10;return num;});list.add(job4);//多任务合并List<Integer> collect =list.stream().map(CompletableFuture<Integer>::join).collect(Collectors.toList());System.out.println(collect);}

  anyOf: 只要在多个 future 里面有一个返回,整个任务就可以结束,而不需要等到每一个future 结束

    private static Integer num = 10;/*** 先对一个数加 10,然后取平方* @param args*/public static void main(String[] args) throws Exception{System.out.println("主线程开始");CompletableFuture<Integer>[] futures = new CompletableFuture[4];CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {try{Thread.sleep(5000);System.out.println("加 10 任务开始");num += 10;return num;}catch (Exception e){return 0;}});futures[0] = job1;CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {try{Thread.sleep(2000);System.out.println("乘以 10 任务开始");num = num * 10;return num;}catch (Exception e){return 1;}});futures[1] = job2;CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {try{Thread.sleep(3000);System.out.println("减以 10 任务开始");num = num * 10;return num;}catch (Exception e){return 2;}});futures[2] = job3;CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {try{Thread.sleep(4000);System.out.println("除以 10 任务开始");num = num * 10;return num;}catch (Exception e){return 3;}});futures[3] = job4;CompletableFuture<Object> future = CompletableFuture.anyOf(futures);System.out.println(future.get());}

第十三章:(1)CompletableFuture异步回调相关推荐

  1. 使用Future实现异步回调的方式

    在JDK5中增加了Future异步获取结果的功能,但是这种方式在获取的时候是阻塞的,在正常场景下这种实现方式肯定是不太友好的,当然可以通过轮询的方式去获取异步结果,但是这种方式比较消耗CPU并且获取结 ...

  2. 【正点原子Linux连载】第五十三章 异步通知实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  3. 第三十一章 线程------GIL、线/近程池、异/同步、异步回调

    一.什么是GIL 官方解释:'''In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple ...

  4. 【正点原子Linux连载】第二十三章 音频应用编程-摘自【正点原子】I.MX6U嵌入式Linux C应用编程指南V1.1

    第二十三章 音频应用编程 ALPHA I.MX6U开发板支持音频,板上搭载了音频编解码芯片WM8960,支持播放以及录音功能! 本章我们来学习Linux下的音频应用编程,音频应用编程相比于前面几个章节 ...

  5. 【系统分析师之路】第十三章 软件体系结构

    [系统分析师之路]第十三章 软件体系结构 软件架构这章节主要的考点有:软件架构的概念,4+1视图,五种软件架构风格(数据流,调用返回,虚拟机,构件,仓库),2层3层CS架构,BS架构,产品线,中间件, ...

  6. 第十三章:python中的并发编程详细讲解

    文章目录 第十三章:并发编程 一.操作系统的基本介绍 (一) 多道技术 一.空间上的复用 二.时间上的复用 (二) 操作系统的作用 (三) 多道技术总结 二.并发编程之进程 (一) 基本概念 一.什么 ...

  7. 【JUC并发编程13】异步回调

    文章目录 13 异步回调 13.1 CompletableFuture 13.2 Future 与 CompletableFuture 13 异步回调 同步:指等待资源(阻塞) 异步:指设立哨兵,资源 ...

  8. stm32 ucosii消息队列 串口_正点原子STM32F407探索者开发板资料连载第六十三章 UCOSII 实验...

    1)实验平台:alientek 阿波罗 STM32F767 开发板 2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 http://weix ...

  9. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高...

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  10. java异步多线程 判断线程状态_java多线程和异步回调

    在实际开发过程中遇到的多线程情况不多,但是在生产环境中多线程是最基本的情况,java面试时也会考到,所以看看多线程的知识还是很有必要的. Thread,Runnable,Callable,Future ...

最新文章

  1. dbcontext mysql_.Net Core 2.0数据库第一种方法Mysql DB的Scaffold-DbContext
  2. 【DotNetMLLearn】.NET Core人工智能系列-概述
  3. zigbee板子:lcd显示汉字
  4. 为什么要写this在访问成员变量的时候_C++幕后故事(一) --对象模型this指针调整...
  5. 官网python安装教程_Python安装教程
  6. Razor语法(三)
  7. 矢量绘图设计工具:Sketch 79 for mac
  8. PeerCDN:使用WebRTC构建基于浏览器的P2P CDN
  9. 数据字典怎么写_做数据分析,我只会同环比,谁能教我怎么写结论?
  10. 服务器 'xxx' 上的 MSDTC 不可用。
  11. 两种方法模仿支付宝进入到后台界面模糊
  12. WIN10系统 插上耳机没声音,解决方案
  13. 为什么医疗行业需要完整的API管理系统?
  14. 内存管理中的 RSS 和 VSZ意思
  15. Epoch, Batch, Iteration 区别
  16. stm32捕获占空比_【电机控制】六步法驱动BLDC电机,使用硬件COM事件,STM32+CUBEMX(HAL库)配置...
  17. 显示器接口_都2019年了,还分不清你的显示器接口?快进来补课!
  18. 【NLP】基于python fasttext的文本分类
  19. JavaScript 按字母顺序排列对象数组
  20. Linux: journal日志文件维护

热门文章

  1. NYOJ 137 取石子(三)(教主神题)
  2. 奥斯汀计算机专业排名,德克萨斯大学奥斯汀分校计算机工程类专业排名
  3. Mac的聚焦搜索Spotlight搜索不准确问题
  4. 关于召回率和hit rate
  5. 苹果手机怎么把计算机放到桌面,苹果怎么投影到电脑_怎么把苹果手机投影到电脑屏幕上-win7之家...
  6. 使用Word脚注、尾注给论文添加参考文献并将编号修改成[1]的方法
  7. 怎么注销百度云服务器账号,百度网盘怎么注销账号?账号注销方法一览
  8. Bloodsucker 【 ZOJ - 3551】
  9. 读书笔记-《20世纪最伟大的心理学实验》读后感1
  10. linux内存中的文件权限,Linux系统管理(用户权限、磁盘存储、文件系统、内存、进程)...