Java多线程开发CompletableFuture的应用
做Java编程,难免会遇到多线程的开发,但是JDK8这个CompletableFuture类很多开发者目前还没听说过,但是这个类实在是太好用了,了解它的一些用法后相信你会对它爱不释手(呸渣男,咋对谁都爱不释手呢),好了我先简单举个列子,告诉你用它有多好。Single Dog拿一个Appointment来举个列子,如下:
/**
* 女神化完妆之后,还需要一小会选衣服,不过分吧。
* 也就是说我们现在有2个异步任务,第一个是化妆,第二个是选衣服。
* 选衣服要在化妆完成之后进行,这两个任务是串行
*/
public static void main(String[] args) {
// 线程池我前面的文章聊过,怎么配置可以去了解一下
ThreadPoolExecutor threadPool= new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
//任务1
CompletableFuture<String> makeUpFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "-女神,开始化妆了");
try {
// 化妆的时间
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "化妆完毕了。";
}, threadPool);
//任务2,makeUp是调用方,意思是makeUpFuture执行完后再执行
CompletableFuture<String> dressFuture = makeUpFuture.thenApply((result) -> {
System.out.println(Thread.currentThread().getName() + "-女神" + result + "我开始选衣服啦,好了叫你!");
try {
// 换衣服的时间
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result + "衣服也选好了,走出去玩吧!";
});
dressFuture.thenAccept((result) -> {
System.out.println(Thread.currentThread().getName() + "-" + result);
});
}
上面的2个任务也可以理解为我们开发中要实现的不同功能,看明白前面的列子了吧?用它来写多线程运用的多丝滑。那我们就先讲一下它的核心的静态的方法,推荐用它的静态方法不要直接new对象。
1:无返回值的静态方法:
public static CompletableFuture<Void> runAsync(Runnable runnable)。
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) 。
上面一个2个方法,如果没有指定Executor就使用默认的ForkJoinPool.commonPool()线程池,如果指定线程池就使用指定的。
2:有返回值的方法
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
如果开始的代码你还看不懂那介绍了上面的几个方法就先小试牛刀一下:
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
int i = 10 / 2;
System.out.println("运行的结果是:" + i);
}, threadPool);
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello World";
}, threadPool);
System.out.println(future.get());
好了讲过它的使用方法了那我们就聊一下它的几个使用的场景,开发中这写场景应该会使用到。
1:执行任务 A,执行任务B,待任务B执行完成后,用B的返回值区执行任务C。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() ->
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行任务A");
return "任务A";
}, executor);
CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
System.out.println("执行任务B");
return "任务B";
}, executor);
CompletableFuture<String> futurec = futureB.thenApply((b) -> {
System.out.println("执行任务C");
System.out.println("参数:" + b);
return "a";
});
System.out.println(futurec.get());
运行结果,注意我上面没说B一定要在A执行以后执行。
场景2:多个任务串联执行,下一个任务的执行依赖上一个任务的结果,每个任务都有输入和输出。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
CompletableFuture futureA = CompletableFuture.supplyAsync(() -> "Hello", executor);
CompletableFuture futureB = futureA.thenApply((a) -> a + " World");
CompletableFuture futureC = futureB.thenApply((b) -> b);
System.out.println(futureC.join());
输出结果,开发中的经典场景输出:

场景3:thenCombineAsync 联合 futureA和futureB的返回结果,然后在返回相关的数据
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> 10, executor);
CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> 20, executor);
CompletableFuture futureC = futureA.thenCombineAsync(futureB, (r1, r2) -> {
System.out.println("r1的值为:" + r1 + ":r2的值为:" + r2);
return r1 + r2;
});
System.out.println(futureC.get());
结果输出:

好了聊完几个场景那就写一个在开发中的经典运用。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
System.out.println("start...");
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品信息1");
return "future1";
}, executor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品信息2");
return "future2";
}, executor);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品信息3");
return "future3";
}, executor);
final CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(future1, future2, future3);
voidCompletableFuture.get();
System.out.println("end...future1的结果:" + future1.get() + ",future2的结果:" + future2.get() + ",future3的结果:" + future3.get());
输出结果

这个经典的应用相信你可以在你的开发中进行套用,然后灵活的运用。当然这个类还有很多的方法,我这里只写了部分介绍了部分场景作为一个引子,如果想了解它的更多的应用可以看它的API的文档。
聊了这么多你应该对我刚开始写的那段代码了如指掌。这么好用的类,欢迎你分享给其他的人,让更多人知晓一下。它运用到开发中,应该能为你的开发提供很多的便利。一束光,二束光,三束光。分享的多了文章慢慢就回也得更好看,更精彩了。

Java多线程开发CompletableFuture的应用的更多相关文章
- Java多线程开发技巧
很多开发者谈到Java多线程开发,仅仅停留在new Thread(...).start()或直接使用Executor框架这个层面,对于线程的管理和控制却不够深入,通过读<Java并发编程实践&g ...
- Java多线程开发系列之番外篇:事件派发线程---EventDispatchThread
事件派发线程是java Swing开发中重要的知识点,在安卓app开发中,也是非常重要的一点.今天我们在多线程开发中,穿插进来这个线程.分别从线程的来由.原理和使用方法三个方面来学习事件派发线程. 一 ...
- Java多线程开发系列之四:玩转多线程(线程的控制2)
在上节的线程控制(详情点击这里)中,我们讲解了线程的等待join().守护线程.本节我们将会把剩下的线程控制内容一并讲完,主要内容有线程的睡眠.让步.优先级.挂起和恢复.停止等. 废话不多说,我们直接 ...
- Java多线程开发系列之一:走进多线程
对编程语言的基础知识:分支.选择.循环.面向对象等基本概念理解后,我们需要对java高级编程有一定的学习,这里不可避免的要接触到多线程开发. 由于多线程开发整体的系统比较大,我会写一个系列的文章总结介 ...
- java多线程开发,Executors、FutureTask、Callable
java多线程如何应用呢,几乎学java的同学都知道Thread类和Runable接口.继承Thread类或者实现Runable接口,调用thread的start方法即可启动线程. 然后是线程池,就是 ...
- Java多线程开发系列之二:如何创建多线程
前文已介绍过多线程的基本知识了,比如什么是多线程,什么又是进程,为什么要使用多线程等等. 在了解了软件开发中使用多线程的基本常识后,我们今天来聊聊如何简单的使用多线程. 在Java中创建多线程的方式有 ...
- Java多线程开发系列之四:玩转多线程(线程的控制1)
在前文中我们已经学习了:线程的基本情况.如何创建多线程.线程的生命周期.利用已有知识我们已经可以写出如何利用多线程处理大量任务这样简单的程序.但是当应用场景复杂时,我们还需要从管理控制入手,更好的操纵 ...
- Java多线程开发系列之三:线程这一辈子(线程的生命周期)
前文中已经提到了,关于多线程的基础知识和多线程的创建.但是如果想要很好的管理多线程,一定要对线程的生命周期有一个整体概念.本节即对线程的一生进行介绍,让大家对线程的各个时段的状态有一定了解. 线程的一 ...
- Java多线程开发系列之五:Springboot 中异步请求方法的使用
Springboot 中异步线程的使用在过往的后台开发中,我们往往使用java自带的线程或线程池,来进行异步的调用.这对于效果来说没什么,甚至可以让开发人员对底层的状况更清晰,但是对于代码的易读性和可 ...
- java多线程开发容易犯的错误
昨天在社区上看到有人讨论多线程使用,多线程遇到一些问题以及一些使用技巧记录一下.为什么要使用多线程, 不能是为了用而用,和设计模式一样用的合理,会让程序更易于理解,用的不合理反而会让程序变得更难理解. ...
随机推荐
- Win10家庭版找不到组策略gpedit.msc怎么解决?
链接:https://pan.baidu.com/s/1SoSWCfHwZhD3tV4C7DcirA 提取码:okfm 1.下载文件 2.以管理员身份运行 3.
- CSR,SSR,PreRender原理解密
CSR.SSR.Prerender 原理全解密 做前端的同学们肯定或多或少听说过CSR,SSR,Prerender这些名词,但是大多肯定只是停留在听说过,了解过,略懂一点,但是,你真的理解这些技术 ...
- count(1) and count(*),count(字段)区别及效率比较
执行结果: count(1)和count(*)之间没有区别,因为count(*)count(1)都不会去过滤空值, count(字段) 会统计该字段在表中出现的次数,忽略字段为null 的情况.即不统 ...
- MySQL事务MVCC、undolog和redolog
MySql的MVCC多版本控制 undolog:回滚日志(保证一致性)只有在ReadCommited和RepeatableRead隔离级别有用 redolog:重写日志(保证持久性) 示例讲解 Rea ...
- git log 查看分支图
操作: 在git config文件里面设置别名. git config --global alias.lg "log --graph --all --pretty=format:'%Cred ...
- SQL server——基础篇之数据完整性
定义:保证数据库中的数据在逻辑上的一致性.正确性和可靠性. 作用:防止无效数据或错误数据进入数据库 数据完整性包括:实体完整性.域完整性和参照完整性 实体完整性 规定表的每一行记录在表中是唯一的 实体 ...
- CAJ转换为PDF
方法就是下载一个CAJViewer和一个PDF虚拟打印机 CAJViewer下载: http://cajviewer.cnki.net/ 我下载了7.2版本 PDF虚拟打印机可以是Adobe acro ...
- 4组-Alpha冲刺-6/6
一.基本情况 队名:摸鲨鱼小队 组长博客:https://www.cnblogs.com/smallgrape/p/15574385.html 小组人数:8人 二.冲刺概况汇报 组长:许雅萍 过去两天 ...
- uni-app微信小程序文本框计数功能
<view> <textarea placeholder="请输入" @input="sumfontnum" :maxlength=" ...
- Day02 差点水掉 欸呀呀
Java狂神6.17星期四 知识行 冯诺依曼+图灵 软件+硬件 .......... 快捷键 ctrl+a 全选 ctrl+x 剪切 alt+F4 关闭窗口 win+r 运行 +cmd命令行 win+ ...