CompletableFuture异步编程
1、创建
/**
* public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier){..}
* public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor){..}
* public static CompletableFuture<Void> runAsync(Runnable runnable){..}
* public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor){..}
*
* @throws ExecutionException
* @throws InterruptedException
*/
@Test
public void testCreateCompletableFuture() throws ExecutionException, InterruptedException {
// 方式一:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " ===> 执行任务,有返回值");
return "qiu";
});
String result = future1.get();
System.out.println("result = " + result);
// 方式二:
ExecutorService pool = Executors.newFixedThreadPool(2);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " ===> 执行任务,有返回值,自定义线程池");
return "qiu";
}, pool);
result = future2.get();
System.out.println("future2 = " + future2);
// 方式三:
CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + " ===> 执行任务,无返回值");
});
// 方式四:
CompletableFuture<Void> future4 = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + " ===> 执行任务,有返回值,自定义线程池");
}, pool);
}
- supplyAsync :执行任务,支持返回值。
- runAsync:执行任务,没有返回值。
2、结果获取
/**
* //方式一
* public T get()
* //方式二
* public T get(long timeout, TimeUnit unit)
* //方式三
* public T getNow(T valueIfAbsent)
* //方式四
* public T join()
*/
@SneakyThrows
@Test
public void testGet(){
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("执行了一个任务");
return "qiu";
});
// getNow()
String futureNow = future.getNow("立刻获取");
System.out.println("futureNow = " + futureNow);
// get(time):超时抛出异常
// String r = future.get(10, TimeUnit.MICROSECONDS);
// System.out.println("r = " + r);
// get()
String result = future.get();
System.out.println("result = " + result);
// join()
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> System.out.println(1 / 0));
future1.join();
}
- get()和get(long timeout, TimeUnit unit) => 在Future中就已经提供了,后者提供超时处理,如果在指定时间内未获取结果将抛出超时异常
- getNow => 立即获取结果不阻塞,结果计算已完成将返回结果或计算过程中的异常,如果未计算完成将返回设定的valueIfAbsent值
- join => 方法里不会抛出异常
3、异步回调方法
thenRun()|thenRunAsync()
/**
无参无返回值 : 做完第一个任务后,再做第二个任务,第二个任务也没有返回值
* thenRun()
* thenRunAsync()
* @throws InterruptedException
*/
@Test
public void testUse() throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(1);
LocalDateTime startTime = LocalDateTime.now();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "第一个任务");
});
// thenRun()
CompletableFuture<Void> future1 = future.thenRun(() -> {
try {
Thread.sleep(400);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "第二个任务");
});
// thenRunAsync()
future1.thenRunAsync(() -> {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "第三个任务");
},pool);
Thread.sleep(1300);
LocalDateTime endTime = LocalDateTime.now();
Duration duration = Duration.between(startTime, endTime);
System.out.println("共耗: " + duration.toHours() + " 小时, " + duration.toMinutes() + " 分钟, "
+ duration.getSeconds() + " 秒, " + duration.toMillis() + " 毫秒");
}
如果你执行第一个任务的时候,传入了一个自定义线程池:
- 调用thenRun方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池。
- 调用thenRunAsync执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoin线程池。
thenAccept()|thenAcceptAsync()
/**
* 有参无返回值:第一个任务执行完成后,执行第二个回调方法任务,会将该任务的执行结果,作为入参,传递到回调方法中,但是回调方法是没有返回值的。
* thenAccept(params)
* thenAcceptAsync(params)
*/
@Test
public void testAccept() throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(2);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "qiu");
CompletableFuture<Void> accept = future.thenAccept((e) -> {
System.out.println("上一个任务的返回值 = " + e);
});
// 无返回值 null
System.out.println("accept.get() = " + accept.get());
CompletableFuture<Void> accept2 = future.thenAcceptAsync((e) -> {
System.out.println("上一个任务的返回值 = " + e);
});
System.out.println("accept2.get() = " + accept2.get());
}
thenApply()|thenApplyAsync()
/**
* 有参有返回值:表示第一个任务执行完成后,执行第二个回调方法任务,会将该任务的执行结果,作为入参,传递到回调方法中,并且回调方法是有返回值的
* thenApply()
* thenApplyAsync()
*/
@Test
public void testApply() throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(2);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "qiu");
CompletableFuture<String> future1 = future.thenApply((e) -> e);
System.out.println("上一个任务的返回值future = " + future1.get());
CompletableFuture<String> future2 = future1.thenApplyAsync((e) -> e, pool);
System.out.println("上一个任务的返回值future1 = " + future2.get());
}
4、异常回调
whenComplete:当CompletableFuture的任务不论是正常完成还是出现异常它都会调用「whenComplete」这个回调函数。
- 正常完成:whenComplete返回结果和上级任务一致,异常为null;
- 出现异常:whenComplete返回结果为null,异常为上级任务的异常;
即调用get()时,正常完成时就获取到结果,出现异常时就会抛出异常,需要你处理该异常
/**
* whenComplete:
*/
@Test
public void testWhenComplete() throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
if (Math.random() < 0.5) {
throw new RuntimeException("出错了!!!");
}
System.out.println("正常结束");
return 11;
}).whenComplete((e, t) -> {
if (e == null) {
System.out.println("whenComplete e is null");
} else {
System.out.println("whenComplete e is " + e);
}
if (t == null) {
System.out.println("whenComplete t is null");
} else {
System.out.println("whenComplete t is " + t.getMessage());
}
});
System.out.println("结果 = " + future.get());
}
whenComplete + exceptionally exceptionally会捕获任务执行中的异常,然后给一个默认的返回值
@Test
public void testWhenComplete() throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
if (Math.random() < 0.5) {
throw new RuntimeException("出错了!!!");
}
System.out.println("正常结束");
return 11;
}).whenComplete((e, t) -> {
if (e == null) {
System.out.println("whenComplete e is null");
} else {
System.out.println("whenComplete e is " + e);
}
if (t == null) {
System.out.println("whenComplete t is null");
} else {
System.out.println("whenComplete t is " + t.getMessage());
}
}).exceptionally(t -> {
System.out.println("出现异常了:" + t.getMessage());
return 0;
});
System.out.println("结果 = " + future.get());
}
结果:
whenComplete e is null
whenComplete t is java.lang.RuntimeException: 出错了!!!
出现异常了:java.lang.RuntimeException: 出错了!!!
结果 = 0
5、多任务组合之 AND
/**
* 多任务组合之 AND
* thenCombine / thenAcceptBoth / runAfterBoth都表示:「当任务一和任务二都完成再执行任务三」。
* 区别在于:
* runAfterBoth: 不会把执行结果当做方法入参,且没有返回值
* thenAcceptBoth: 会将两个任务的执行结果作为方法入参,传递到指定方法中,且无返回值
* thenCombine: 会将两个任务的执行结果作为方法入参,传递到指定方法中,且有返回值
*/
@Test
public void testAnd() throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务1结束");
return result;
}, executorService);
//开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务2,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务2结束");
return result;
}, executorService);
//任务组合
CompletableFuture<Integer> task3 = task.thenCombineAsync(task2, (f1, f2) -> {
System.out.println("执行任务3,当前线程是:" + Thread.currentThread().getId());
System.out.println("任务1返回值:" + f1);
System.out.println("任务2返回值:" + f2);
return f1 + f2;
}, executorService);
Integer res = task3.get();
System.out.println("最终结果:" + res);
}
6、多任务组合之 OR
/**
* 多任务组合之 OR
* applyToEither / acceptEither / runAfterEither 都表示:「两个任务,只要有一个任务完成,就执行任务三」。
* 区别在于:
* runAfterEither:不会把执行结果当做方法入参,且没有返回值
* acceptEither: 会将已经执行完成的任务,作为方法入参,传递到指定方法中,且无返回值
* applyToEither:会将已经执行完成的任务,作为方法入参,传递到指定方法中,且有返回值
*/
@Test
public void testOR() {
// 创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务1结束");
return result;
}, executorService);
// 开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务2,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 2;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务2结束");
return result;
}, executorService);
// 任务组合
task.acceptEitherAsync(task2, (res) -> {
System.out.println("执行任务3,当前线程是:" + Thread.currentThread().getId());
System.out.println("上一个任务的结果为:" + res);
}, executorService);
}
7、多任务组合
allOf:等待所有任务完成
@Test
public void testallOf() throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务1结束");
return result;
}, executorService);
//开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务2,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 2;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务2结束");
return result;
}, executorService);
//开启异步任务3
CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务3,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 3;
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务3结束");
return result;
}, executorService);
//任务组合,这里可以理解为,当我们需要去其他系统调用数据时,组合所有任务
CompletableFuture<Void> allOf = CompletableFuture.allOf(task, task2, task3);
//等待所有任务完成
allOf.get();
//获取任务的返回结果
System.out.println("task结果为:" + task.get());
System.out.println("task2结果为:" + task2.get());
System.out.println("task3结果为:" + task3.get());
}
anyOf() : 只要有一个任务完成
@Test
public void testAnyOf() throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务1结束");
return result;
}, executorService);
//开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务2,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 2;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务2结束");
return result;
}, executorService);
//开启异步任务3
CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务3,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 3;
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务3结束");
return result;
}, executorService);
//任务组合,这里可以理解为,当我们需要去其他系统调用数据时,组合所有任务
CompletableFuture<Object> future = CompletableFuture.anyOf(task, task2, task3);
//某一人任务完成
Object res = future.get();
System.out.println("res = " + res);
//获取任务的返回结果
System.out.println("task结果为:" + task.get());
System.out.println("task2结果为:" + task2.get());
System.out.println("task3结果为:" + task3.get());
}
CompletableFuture异步编程的更多相关文章
- 编程老司机带你玩转 CompletableFuture 异步编程
本文从实例出发,介绍 CompletableFuture 基本用法.不过讲的再多,不如亲自上手练习一下.所以建议各位小伙伴看完,上机练习一把,快速掌握 CompletableFuture. 个人博文地 ...
- 带你玩转CompletableFuture异步编程
前言 最近在忙生活的第一个OKR,这个等等后面具体聊聊,今天开始恢复每周一篇原创,感谢小伙伴的不离不弃.这篇文章也是最近在Code Review的时候,看到的大家代码,想整体推下大家异步编程的思想,由 ...
- Java8系列 (七) CompletableFuture异步编程
概述 Java8之前用 Future 处理异步请求, 当你需要获取任务结果时, 通常的做法是调用 get(long timeout, TimeUnit unit) 此方法会阻塞当前的线程, 如果任务 ...
- 从CompletableFuture到异步编程设计
从CompletableFuture到异步编程设计,笔者就分为2部分来分享CompletableFuture异步编程设计,前半部分总结下CompletableFuture使用实践,后半部分分享下Com ...
- 异步编程利器:CompletableFuture
一.一个示例回顾Future 一些业务场景我们需要使用多线程异步执行任务,加快任务执行速度. JDK5新增了Future接口,用于描述一个异步计算的结果.虽然 Future 以及相关使用方法提供了异步 ...
- 异步编程CompletableFuture实现高并发系统优化之请求合并
先说场景: 根据Redis官网介绍,单机版Redis的读写性能是12万/秒,批量处理可以达到70万/秒.不管是缓存或者是数据库,都有批量处理的功能.当我们的系统达到瓶颈的时候,我们考虑充分的压榨缓存和 ...
- 有了 CompletableFuture,使得异步编程没有那么难了!
本文导读: 业务需求场景介绍 技术设计方案思考 Future 设计模式实战 CompletableFuture 模式实战 CompletableFuture 生产建议 CompletableFutur ...
- 搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文
你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...
- 异步编程CompletableFuture
多线程优化性能,串行操作并行化 串行操作 // 以下2个都是耗时操作 doBizA(); doBizB(); 修改变为并行化 new Thread(() -> doBizA()).start() ...
- Atitit.异步编程技术原理与实践attilax总结
Atitit.异步编程技术原理与实践attilax总结 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模 ...
随机推荐
- 《Kali渗透基础》15. WEB 渗透
@ 目录 1:WEB 技术 1.1:WEB 攻击面 1.2:HTTP 协议基础 1.3:AJAX 1.4:WEB Service 2:扫描工具 2.1:HTTrack 2.2:Nikto 2.3:Sk ...
- 【故障公告】一而再,再而三,三翻四复:数据库服务器 CPU 100%
会员救园,故障捣乱,每当困难时,故障们总是喜欢雪上加霜过来考验你. 今天下班前 17:43~17:47 期间,园子的 SQL Server 数据库服务器突然出现 CPU 100% 问题. 发现问题后, ...
- 如何使用Vite创建Vue3的uniapp项目
项目结构 my-vue3-project ├─ .env //默认环境变量 ├─ .env.development //开发环境变量 ├─ .eslintrc-auto-import.json //( ...
- Go协程揭秘:轻量、并发与性能的完美结合
Go协程为并发编程提供了强大的工具,结合轻量级.高效的特点,为开发者带来了独特的编程体验.本文深入探讨了Go协程的基本原理.同步机制.高级用法及其性能与最佳实践,旨在为读者提供全面.深入的理解和应用指 ...
- 【爬虫笔记】Python爬虫简单运用爬取代理IP
一.前言 近些年来,网络上的爬虫越来越多,很多网站都针对爬虫进行了限制,封禁了一些不规则的请求.为了实现正常的网络爬虫任务,爬虫常用代理IP来隐藏自己的真实IP,避免被服务器封禁.本文将介绍如何使用P ...
- torch.nn.ReLU(inplace=True)的具体含义:
首先根据源文档中的ReLU(x)=max(0,x),得出结论.大于0的数值不变,小于0的数据变成0. 补充:这里需要注意的是 ReLU并没有限制数据的大小. 这是对应的文档链接:https://pyt ...
- PHP-basename
basename 定义: basename() 函数返回路径中的文件名部分. 语法: basename(path,suffix) 参数 描述 path 必需.规定要检查的路径 suffix 可选.规定 ...
- Qt信号槽与事件循环学习笔记
事件与事件循环 信号槽机制 事件与事件循环 在Qt中,事件(event)被封装为QEvent类/子类对象,用来表示应用内部或外部发生的各种事情.事件可以被任何QObject子类的对象接收并处理. 根据 ...
- 【PHP反序列化】速览
PHP反序列化 一.原理 序列化就是将对象转化成字符串,反序列化相反.数据的格式转换和对象的序列化有利于对象的保存 . 反序列化漏洞:就是php对数据进行反序列化时,没有进行过滤,导致用户可以控制反序 ...
- 2D物理引擎 Box2D for javascript Games 第五章 碰撞处理
2D物理引擎 Box2D for javascript Games 第五章 碰撞处理 碰撞处理 考虑到 Box2D 世界和在世界中移动的刚体之间迟早会发生碰撞. 而物理游戏的大多数功能则依赖于碰撞.在 ...