Java多线程开发工具之CompletableFuture的应用详解
作者:程序员xiaozhang 发布时间:2023-08-30 00:43:00
做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的文档。
来源:https://www.cnblogs.com/scott1102/p/17233824.html


猜你喜欢
- 公司的老项目要改造多租户,于是进入了大坑,本文写点遇到的坑以及解决方案,每次遇到问题在网上搜了好久,记录下来,防止以后忘掉。(一).方案网上
- package com.infomorrow.parser_report;import org.junit.Test;public clas
- 一、目标效果聊天会话页的列表效果1、聊天数据不满一屏时,顶部显示所有聊天数据2、插入消息时如果最新消息紧靠列表底部时,则插入消息会使列表向上
- 在编程的时候或者写网络爬虫的时候,经常需要对html进行解析,抽取其中有用的数据。一款好的工具是特别有用的,能提供很多的帮助,网上有很多这样
- 缓存可以说是加速服务响应速度的一种非常有效并且简单的方式。在缓存领域,有很多知名的框架,如EhCache 、Guava、HazelCast等
- 前言对于信息的加密方式多种多样,之前为大家介绍了一种自己设计的加密方式,有兴趣的朋友可以欣赏一下,欢迎给予指点。今天为大家介绍一下对称加密方
- Spring Cloud Gateway去掉url前缀主要是增加一个 route,其他配置不变routes: - id: ser
- 1. 前言什么是特殊矩阵?C++,一般使用二维数组存储矩阵数据。在实际存储时,会发现矩阵中有许多值相同的数据或有许多零数据,且分布呈现出一定
- 本文介绍了Maven构建自己的第一个Java后台的方法,分享给大家,具体如下:1.知识后顾关于如何运用Maven构建自己的第一个项目,上期我
- 面试课题 Spring boot AOPSpring boot 中 AOP是其中 重要的特性,其实现的方式借助的 * + Proxy 动态
- 本文实例为大家分享了C# Winform实现圆角无锯齿按钮的具体代码,供大家参考,具体内容如下发现用Winform做一个圆角按钮遇到麻烦,主
- 创建一个maven项目导入springboot依赖,注意底 * 释部分<?xml version="1.0&quo
- 滑动删除的部分主要包含两个部分, 一个是内容区域(用于放置正常显示的view),另一个是操作区域(用于放置删除按钮)。默认情况下,操作区域是
- 简介石头剪刀布游戏,进入游戏后,玩家需要输入玩家姓名。系统界面之后弹出欢迎界面,玩家可以选择出拳或者退出游戏。玩家选择出拳后同电脑出拳比较,
- 表示键/值对的集合,这些键和值按键排序并可按照键和索引访问。SortedList最合适对一列健/值对 进行排序,在排序时,是对键进行排序,S
- java中的前加加++和后加加++,有很多人搞的很晕,不太明白!今天我举几个例子说明下前++和后++的区别!其实大家只要记住一句话就可以了,
- 前言最近在学习安卓开发的时候遇到了一个问题,使用Android Studio在为Button设置背景颜色的时候发现设置好后却在运行 * 上失
- 将通用算法放入具体类(HeapSorter),并将通用算法必须调用的方法定义在接口(HeapSorterHandle)中,从这个接口派生出D
- 在字符集中,有一类字符具有这样的特性:当从键盘上输入这个字符时,显示器上就可以显示这个字符,即输入什么就显示什么。这类字符称为可显示字符,如
- 导语本章根据百度地图API,实现仿钉钉打卡功能。用到了基础地图、覆盖物、定位图层、陀螺仪方法、悬浮信息弹框。百度地图API地址