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异步编程的更多相关文章

  1. 编程老司机带你玩转 CompletableFuture 异步编程

    本文从实例出发,介绍 CompletableFuture 基本用法.不过讲的再多,不如亲自上手练习一下.所以建议各位小伙伴看完,上机练习一把,快速掌握 CompletableFuture. 个人博文地 ...

  2. 带你玩转CompletableFuture异步编程

    前言 最近在忙生活的第一个OKR,这个等等后面具体聊聊,今天开始恢复每周一篇原创,感谢小伙伴的不离不弃.这篇文章也是最近在Code Review的时候,看到的大家代码,想整体推下大家异步编程的思想,由 ...

  3. Java8系列 (七) CompletableFuture异步编程

    概述 Java8之前用 Future 处理异步请求, 当你需要获取任务结果时, 通常的做法是调用  get(long timeout, TimeUnit unit) 此方法会阻塞当前的线程, 如果任务 ...

  4. 从CompletableFuture到异步编程设计

    从CompletableFuture到异步编程设计,笔者就分为2部分来分享CompletableFuture异步编程设计,前半部分总结下CompletableFuture使用实践,后半部分分享下Com ...

  5. 异步编程利器:CompletableFuture

    一.一个示例回顾Future 一些业务场景我们需要使用多线程异步执行任务,加快任务执行速度. JDK5新增了Future接口,用于描述一个异步计算的结果.虽然 Future 以及相关使用方法提供了异步 ...

  6. 异步编程CompletableFuture实现高并发系统优化之请求合并

    先说场景: 根据Redis官网介绍,单机版Redis的读写性能是12万/秒,批量处理可以达到70万/秒.不管是缓存或者是数据库,都有批量处理的功能.当我们的系统达到瓶颈的时候,我们考虑充分的压榨缓存和 ...

  7. 有了 CompletableFuture,使得异步编程没有那么难了!

    本文导读: 业务需求场景介绍 技术设计方案思考 Future 设计模式实战 CompletableFuture 模式实战 CompletableFuture 生产建议 CompletableFutur ...

  8. 搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  9. 异步编程CompletableFuture

    多线程优化性能,串行操作并行化 串行操作 // 以下2个都是耗时操作 doBizA(); doBizB(); 修改变为并行化 new Thread(() -> doBizA()).start() ...

  10. Atitit.异步编程技术原理与实践attilax总结

    Atitit.异步编程技术原理与实践attilax总结 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模 ...

随机推荐

  1. 【升职加薪秘籍】我在服务监控方面的实践(8)-elasticsearch 性能监控与分析手段

    大家好,我是蓝胖子,之前讲了mysql,redis中间件的监控,今天我们再来看看另一个基础组件elasticsearch,如何对它进行监控,当你思考如何对一个组件进行监控时,四大黄金指标会告诉你答案, ...

  2. H.265+SRS6.0服务器部署

    H.265+SRS6.0服务器部署 SRS从6.0开始,全面支持H.265,包括RTMP.FLV.HLS.GB28181.WebRTC等等.具体的服务器部署及H.265推流步骤如下. 1. SRS 要 ...

  3. Mac m2使用实现微信小程序抓包

    Mac m2使用实现微信小程序抓包 最近换了MacBook Pro,芯片是M2 Pro,很多东西跟windows是不一样的,所以重新配置相应环境,这里介绍一下微信小程序抓包的方法. 使用burp+pr ...

  4. 如何理解SpringBoot的Starter

    Starter是SpringBoot的四大核心功能特性之一,除此之外,SpringBoot还有自动装配,Actuator监控等特性 SpringBoot里面的这些特性,都是为了让开发者在开发基于Spr ...

  5. 提取protobuf定义文件结构

    先安装protobuf的js支持包 npm install protobufjs test.proto文件如下所示 syntax = "proto3"; package Test; ...

  6. 你准备好了吗,9月19日Java21要来了

    前言 9月份的TIOBE编程语言榜单已公布,Python依然是第一,Java第四. 而这个月还有一个重要的事情,就是9月19日Java21将会全面发布,一段时间没关注的我一口老血喷在屏幕上. 我记得我 ...

  7. 小知识:PPT的幻灯片放映设置

    最近给某客户讲课时,碰到了幻灯片自动翻页的情况,发现是因为之前做过粗略的计时演练,有些片子就快速过了. 问题现象: 结果导致放映时也出现了某些片子快速被自动翻页. 解决方案: 设置成手动推进幻灯片的方 ...

  8. window操作系统安装多个版本nodejs版本-控制工具nvm

    参考: https://blog.csdn.net/m0_38134431/article/details/118388297 https://juejin.cn/post/7044890876631 ...

  9. Hyper-V安装Ubuntu16.04,连接网络的设置

    使用Windows10自带的Hyper-V安装Ubuntu. 进入系统界面后,无法连接网络. 1.首先确定安装虚拟机的网络设置 2.在Wlan属性分享页面中选取对应的网络设置,然后回到属性页面勾选Hy ...

  10. 文心一言 VS 讯飞星火 VS chatgpt (114)-- 算法导论10.2 7题

    七.用go语言,给出一个 O(n)时间的非递归过程,实现对一个含 n个元素的单链表的逆转.要求除存储链表本身所需的空间外,该过程只能使用固定大小的存储空间. 文心一言: 在Go语言中,你可以使用迭代方 ...