CompletableFuture API介绍及使用
1. 介绍
CompletableFuture 是 Java 8 引入的一个用于异步编程的类,位于 java.util.concurrent 包中。它是对 Future 的增强,提供了更强大的功能来支持异步任务的编排、组合和处理。
2. 方法
不使用自定义线程池,会使用ForkJoinPool中的共用线程池CommonPool(CommonPool的大小是CPU核数-1,如果是IO密集的应用,线程数可能成为瓶颈)
2.1 异步执行,不需要结果
使用默认线程池
CompletableFuture<Void> future1 = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
// 逻辑
}
});
使用自定义线程池
CompletableFuture<Void> future2 = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
// 逻辑
}
}, executor);
2.2 异步执行,需要结果
使用默认线程池
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
// 逻辑写在这里
return "result"; // 结果类型 可以修改T public interface Supplier<T>{}
}
});
使用自定义线程池
CompletableFuture<String> future4 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
// 逻辑写在这里
return "result"; // 结果类型 可以修改T public interface Supplier<T>{}
}
}, executor);
2.3 thenRun() 同步执行 thenRunAsync() 异步执行
CompletableFuture<Void> future5 = future1.thenRun(new Runnable() {
@Override
public void run() {
// 逻辑
}
});
2.4 thenApply() 同步执行 thenApplyAsync() 异步执行
CompletableFuture<String> future6 = future3.thenApply(new Function<String, String>() {
@Override
public String apply(String s) {
return "result";
}
});
2.5 thenAccept() 同步执行 thenAcceptAsync() 异步执行, 与 thenRun 不同, thenAccept 存在入参
CompletableFuture<Void> future7 = future3.thenAccept(new Consumer<String>() {
@Override
public void accept(String s) {
// 逻辑
}
});
2.6 thenAcceptBoth、thenAcceptBothAsync() 两个 future 全部执行完成,才会执行
CompletableFuture<Void> future8 = future3.thenAcceptBoth(future4, new BiConsumer<String, String>() {
// 获取俩个 future 的结果
@Override
public void accept(String s8, String s4) {
}
});
2.7 applyToEither()、applyToEitherAsync() 两个 future 任意一个执行完成,才会执行
CompletableFuture<String> future9 = future3.applyToEither(future4, new Function<String, String>() {
@Override
public String apply(String s) {
return s;
}
});
2.8 acceptEither 消费 future6 和 future4 的任意一个结果,并消费
CompletableFuture<Void> future10 = future6.acceptEither(future4, new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
2.9 thenCompose()、thenComposeAsync() 新建一个 CompletableFuture,并返回
CompletableFuture<String> future11 = future3.thenCompose(new Function<String, CompletableFuture<String>>() {
@Override
public CompletableFuture<String> apply(String s) {
return CompletableFuture.supplyAsync(() -> s + " World");
}
});
2.10 thenCombine()、thenCombineAsync()
CompletableFuture<String> future12 = future3.thenCombine(future4, new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return s + s2;
}
});
2.11 whenComplete()、whenCompleteAsync() 不会吞掉异常
CompletableFuture<String> future13 = future3.whenComplete(new BiConsumer<String, Throwable>() {
@Override
public void accept(String s, Throwable throwable) {
System.out.println(s);
}
});
2.12 handle()、handleAsync() 会吞掉异常
CompletableFuture<String> future14 = future3.handle(new BiFunction<String, Throwable, String>() {
@Override
public String apply(String s, Throwable throwable) {
return s;
}
});
2.13 exceptionally()
CompletableFuture<String> future15 = future3.exceptionally(new Function<Throwable, String>() {
@Override
public String apply(Throwable throwable) {
return "error";
}
});
2.14 allOf()、anyOf()
CompletableFuture<Void> future16 = CompletableFuture.allOf(future3, future4); // allOf() 是同步所有任务结果,而不需要进行处理他们的结果
CompletableFuture<Object> future17 = CompletableFuture.anyOf(future3, future4); // anyOf() 是等待其中一个future处理完成,并返回结果
3 使用场景
3.1 例子1
如图所示,各个流程之间有相关依赖,比如执行CF4需要CF1、CF2的结果:

CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "cf1 result"); // 异步执行有返回值
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> "cf2 result");
CompletableFuture<String> cf3 = cf1.thenApply(s -> "cf3 result");
CompletableFuture<String> cf4 = cf1.thenCombineAsync(cf2, (s1, s2) -> {
System.out.println("cf1 result: " + s1);
System.out.println("cf2 result: " + s2);
return "cf4 result";
});
CompletableFuture<String> cf5 = cf2.thenApply(s -> "cf5 result");
CompletableFuture<Void> cf6 = CompletableFuture.allOf(cf3, cf4, cf5);
String cf6Result = cf6.thenApply(v -> {
cf3.join();
cf4.join();
cf5.join();
return "cf6 result";
}).get();
System.out.println(cf6Result);
3.2 例子2
ExecutorService executor = Executors.newFixedThreadPool(5);
//1、使用runAsync或supplyAsync发起异步调用
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
return "result1";
}, executor);
//2、CompletableFuture.completedFuture()直接创建一个已完成状态的CompletableFuture
//使用场景为缓存,命中缓存直接返回
CompletableFuture<String> cf2 = CompletableFuture.completedFuture("result2");
//3、先初始化一个未完成的CompletableFuture,然后通过complete()、completeExceptionally(),完成该CompletableFuture
//使用场景为回调机制、超时处理、任务取消等场景。
CompletableFuture<String> cf2 = new CompletableFuture<>();
cf.complete("success");
4. 问题
合理使用线程池,避免死锁
ExecutorService threadPool1 = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(100));
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
return CompletableFuture.supplyAsync(() -> {
System.out.println("child");
return "child";
}, threadPool1).join();// 子任务
}, threadPool1);
future.join();
System.out.println("main");
上面的例子中,当10个线程同事请求时,父类future将10个线程获取,子类不能获取线程导致死锁出现。
5. 总结
| 函数 | 使用方式 | 使用场景 |
|---|---|---|
| runAsync | CompletableFuture.runAsync(Runnable task) |
异步执行一个无返回值的任务。 |
| runAsync | CompletableFuture.runAsync(Runnable task, Executor executor) |
异步执行一个无返回值的任务,使用自定义线程池。 |
| supplyAsync | CompletableFuture.supplyAsync(Supplier<T> supplier) |
异步执行一个有返回值的任务。 |
| supplyAsync | CompletableFuture.supplyAsync(Supplier<T> supplier, Executor executor) |
异步执行一个有返回值的任务,使用自定义线程池。 |
| thenRun | future.thenRun(Runnable action) |
在前一个任务完成后,同步执行一个无返回值的操作。 |
| thenRunAsync | future.thenRunAsync(Runnable action) |
在前一个任务完成后,异步执行一个无返回值的操作。 |
| thenApply | future.thenApply(Function<T, U> fn) |
在前一个任务完成后,同步处理其结果并返回新值。 |
| thenApplyAsync | future.thenApplyAsync(Function<T, U> fn) |
在前一个任务完成后,异步处理其结果并返回新值。 |
| thenAccept | future.thenAccept(Consumer<T> action) |
在前一个任务完成后,同步消费其结果(无返回值)。 |
| thenAcceptAsync | future.thenAcceptAsync(Consumer<T> action) |
在前一个任务完成后,异步消费其结果(无返回值)。 |
| thenAcceptBoth | future1.thenAcceptBoth(future2, BiConsumer<T, U> action) |
在两个任务都完成后,同步消费它们的结果(无返回值)。 |
| thenAcceptBothAsync | future1.thenAcceptBothAsync(future2, BiConsumer<T, U> action) |
在两个任务都完成后,异步消费它们的结果(无返回值)。 |
| applyToEither | future1.applyToEither(future2, Function<T, U> fn) |
在两个任务中任意一个完成后,同步处理其结果并返回新值。 |
| applyToEitherAsync | future1.applyToEitherAsync(future2, Function<T, U> fn) |
在两个任务中任意一个完成后,异步处理其结果并返回新值。 |
| acceptEither | future1.acceptEither(future2, Consumer<T> action) |
在两个任务中任意一个完成后,同步消费其结果(无返回值)。 |
| acceptEitherAsync | future1.acceptEitherAsync(future2, Consumer<T> action) |
在两个任务中任意一个完成后,异步消费其结果(无返回值)。 |
| thenCompose | future.thenCompose(Function<T, CompletableFuture<U>> fn) |
在前一个任务完成后,同步启动一个新的 CompletableFuture。 |
| thenComposeAsync | future.thenComposeAsync(Function<T, CompletableFuture<U>> fn) |
在前一个任务完成后,异步启动一个新的 CompletableFuture。 |
| thenCombine | future1.thenCombine(future2, BiFunction<T, U, V> fn) |
在两个任务都完成后,同步处理它们的结果并返回新值。 |
| thenCombineAsync | future1.thenCombineAsync(future2, BiFunction<T, U, V> fn) |
在两个任务都完成后,异步处理它们的结果并返回新值。 |
| whenComplete | future.whenComplete(BiConsumer<T, Throwable> action) |
在前一个任务完成后,同步处理其结果或异常(不改变结果或异常)。 |
| whenCompleteAsync | future.whenCompleteAsync(BiConsumer<T, Throwable> action) |
在前一个任务完成后,异步处理其结果或异常(不改变结果或异常)。 |
| handle | future.handle(BiFunction<T, Throwable, U> fn) |
在前一个任务完成后,同步处理其结果或异常,并返回新值(可覆盖异常)。 |
| handleAsync | future.handleAsync(BiFunction<T, Throwable, U> fn) |
在前一个任务完成后,异步处理其结果或异常,并返回新值(可覆盖异常)。 |
| exceptionally | future.exceptionally(Function<Throwable, T> fn) |
在前一个任务失败时,同步处理异常并返回备用值。 |
| allOf | CompletableFuture.allOf(future1, future2, ...) |
等待所有任务完成(无返回值)。 |
| anyOf | CompletableFuture.anyOf(future1, future2, ...) |
等待任意一个任务完成,并返回其结果(返回 Object 类型)。 |
附录
美团工具类 : CompletableFuture原理与实践-外卖商家端API的异步化
import lombok.extern.slf4j.Slf4j;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.BinaryOperator;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* CompletableFuture封装工具类
*/
@Slf4j
public class FutureUtils {
/**
* 设置CF状态为失败
*/
public static <T> CompletableFuture<T> failed(Throwable ex) {
CompletableFuture<T> completableFuture = new CompletableFuture<>();
completableFuture.completeExceptionally(ex);
return completableFuture;
}
/**
* 设置CF状态为成功
*/
public static <T> CompletableFuture<T> success(T result) {
CompletableFuture<T> completableFuture = new CompletableFuture<>();
completableFuture.complete(result);
return completableFuture;
}
/**
* 将List<CompletableFuture<T>> 转为 CompletableFuture<List<T>>
*/
public static <T> CompletableFuture<List<T>> sequence(Collection<CompletableFuture<T>> completableFutures) {
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList())
);
}
/**
* 将List<CompletableFuture<List<T>>> 转为 CompletableFuture<List<T>>
* 多用于分页查询的场景
*/
public static <T> CompletableFuture<List<T>> sequenceList(Collection<CompletableFuture<List<T>>> completableFutures) {
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream()
.flatMap(listFuture -> listFuture.join().stream())
.collect(Collectors.toList())
);
}
/*
* 将List<CompletableFuture<Map<K, V>>> 转为 CompletableFuture<Map<K, V>>
* @Param mergeFunction 自定义key冲突时的merge策略
*/
public static <K, V> CompletableFuture<Map<K, V>> sequenceMap(
Collection<CompletableFuture<Map<K, V>>> completableFutures, BinaryOperator<V> mergeFunction) {
return CompletableFuture
.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream().map(CompletableFuture::join)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, mergeFunction)));
}
/**
* 将List<CompletableFuture<T>> 转为 CompletableFuture<List<T>>,并过滤调null值
*/
public static <T> CompletableFuture<List<T>> sequenceNonNull(Collection<CompletableFuture<T>> completableFutures) {
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream()
.map(CompletableFuture::join)
.filter(e -> e != null)
.collect(Collectors.toList())
);
}
/**
* 将List<CompletableFuture<List<T>>> 转为 CompletableFuture<List<T>>,并过滤调null值
* 多用于分页查询的场景
*/
public static <T> CompletableFuture<List<T>> sequenceListNonNull(Collection<CompletableFuture<List<T>>> completableFutures) {
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream()
.flatMap(listFuture -> listFuture.join().stream().filter(e -> e != null))
.collect(Collectors.toList())
);
}
/**
* 将List<CompletableFuture<Map<K, V>>> 转为 CompletableFuture<Map<K, V>>
*
* @Param filterFunction 自定义过滤策略
*/
public static <T> CompletableFuture<List<T>> sequence(Collection<CompletableFuture<T>> completableFutures,
Predicate<? super T> filterFunction) {
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream()
.map(CompletableFuture::join)
.filter(filterFunction)
.collect(Collectors.toList())
);
}
/**
* 将List<CompletableFuture<List<T>>> 转为 CompletableFuture<List<T>>
*
* @Param filterFunction 自定义过滤策略
*/
public static <T> CompletableFuture<List<T>> sequenceList(Collection<CompletableFuture<List<T>>> completableFutures,
Predicate<? super T> filterFunction) {
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream()
.flatMap(listFuture -> listFuture.join().stream().filter(filterFunction))
.collect(Collectors.toList())
);
}
/**
* 将CompletableFuture<Map<K,V>>的list转为 CompletableFuture<Map<K,V>>。 多个map合并为一个map。 如果key冲突,采用新的value覆盖。
*/
public static <K, V> CompletableFuture<Map<K, V>> sequenceMap(
Collection<CompletableFuture<Map<K, V>>> completableFutures) {
return CompletableFuture
.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
.thenApply(v -> completableFutures.stream().map(CompletableFuture::join)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b)));
}
}
CompletableFuture API介绍及使用的更多相关文章
- CompletableFuture用法介绍
一.CompletableFuture用法入门介绍 入门介绍的一个例子: package com.cy.java8; import java.util.Random; import java.util ...
- 常用ArcGIS for Silverlight 开发API介绍
1.API介绍 2.Map对象 3.Layer对象 4.Symbol对象 5.Task对象
- Servlet基础(一) Servlet简介 关键API介绍及结合源码讲解
Servlet基础(一) Servlet基础和关键的API介绍 Servlet简介 Java Servlet是和平台无关的服务器端组件,它运行在Servlet容器中. Servlet容器负责Servl ...
- python学习笔记(win32print API介绍)
最近博主在研究用python控制打印机 这里整理下win32print的API介绍,官网地址http://timgolden.me.uk/pywin32-docs/win32print.html Op ...
- 使用html5中video自定义播放器必备知识点总结以及JS全屏API介绍
一.video的js知识点: controls(控制器).autoplay(自动播放).loop(循环)==video默认的: 自定义播放器中一些JS中提供的方法和属性的记录: 1.play()控制视 ...
- Commons-lang API介绍
4.1 Commons-lang API介绍 4.1.1 StringUtils 4.1.2 StringEscapeUtils 4.1.3 ArrayUtils 4.1.4 DateUtils 4. ...
- APP自动化框架LazyAndroid使用手册(3)--核心API介绍
作者:黄书力 概述 在前一篇博文中,简要介绍了一款安卓UI自动化测试框架LazyAndroid (http://blog.csdn.net/kaka1121/article/details/53204 ...
- Spring Boot 2.x 编写 RESTful API (一) RESTful API 介绍 & RestController
用Spring Boot编写RESTful API 学习笔记 RESTful API 介绍 REST 是 Representational State Transfer 的缩写 所有的东西都是资源,所 ...
- FastDFS api介绍
1. 命令行api介绍 FastDFS提供了可用于运维测试的命令行api,下面进行介绍: 1.1 fastdfs服务管理 tracker进程服务管理脚本 /etc/init.d/fdfs_tracke ...
- ElasticSearch的API介绍
ElasticSearch的API介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.ES是基于Restful风格 1>ES是基于Restful风格 Elasticsea ...
随机推荐
- Qt编写地图综合应用27-点聚合
一.前言 在地图上查询结果通常以标记点的形式展现,但是如果标记点较多,不仅会大大增加客户端的渲染时间,让客户端变得很卡,而且会让人产生密集恐惧症.为了解决这一问题,我们需要一种手段能在用户有限的可视区 ...
- [转]基于GMap.Net的地图解决方案
一 地图的加载与显示 关于GMap的介绍与使用可以看我以前的文章: GMap.Net开发之在WinForm和WPF中使用GMap.Net地图插件 GMap.Net是.Net下一个地图控件,可以基于Ht ...
- Rust远程加载shellcode
学习rust, 练习写一个loader, 不足之处还请指教 编写 隐藏黑框 在注释掉所有打印语句后编译运行还是会弹黑框, 解决方法是头部添加一行(指定 Rust 编译器生成的可执行文件为 Window ...
- Chrome谷歌浏览器自动升级后页面字体过小
谷歌浏览器使用一段时间后系统自动升级后页面字体突然变小,如何进行设置呢,如下 1.在页面右上角选择浏览器设置-外观-自定义字体-设置字号等其他需要配置的参数即可
- SpringCloud (五) - 云服务器Centos7.6,安装JDK,Maven,Mysql,Redis
1.购买云服务器 购买地址:https://cloud.tencent.com/act/pro/2022double11_warmup 后面的环境都是基于此环境Centos7.6: 2.安装 Secu ...
- Golang-编译和工具链12
http://c.biancheng.net/golang/build/ go build命令(go语言编译命令)完全攻略 Go语言的编译速度非常快.Go 1.9 版本后默认利用Go语言的并发特性进行 ...
- Java中,将ResultSet映射为对象和队列及其他辅助函数
关于对象关系映射(ORM)在数据库访问中用到的最多,在Java中,很多库都试图将一个ResultSet映射为一个自定义的Java Bean对象或队列,下面是我的实现 1 从ResultSet中读取数据 ...
- 面试题:关于StringBuffer()源码的深度理解Debug分析
import org.junit.Test; /** * @author CH * @create 2021 上午 11:23 */ public class IDEADebug { @Test pu ...
- java中匿名类,Bean规范,全局变量
实现看见一个人,我们对它说hello public class study01 { public static void main(String[] args) { Me me = new Me(); ...
- 小程序uni-app图片预览uni.previewImage会触发onshow这个生命周期
小程序单张uni-app图片预览 uni.previewImage({ current:0, urls: [mess.honorIcon],//['你的图片地址'] }); 小程序多张图片预览 < ...