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. 《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 ...

  2. 【故障公告】一而再,再而三,三翻四复:数据库服务器 CPU 100%

    会员救园,故障捣乱,每当困难时,故障们总是喜欢雪上加霜过来考验你. 今天下班前 17:43~17:47 期间,园子的 SQL Server 数据库服务器突然出现 CPU 100% 问题. 发现问题后, ...

  3. 如何使用Vite创建Vue3的uniapp项目

    项目结构 my-vue3-project ├─ .env //默认环境变量 ├─ .env.development //开发环境变量 ├─ .eslintrc-auto-import.json //( ...

  4. Go协程揭秘:轻量、并发与性能的完美结合

    Go协程为并发编程提供了强大的工具,结合轻量级.高效的特点,为开发者带来了独特的编程体验.本文深入探讨了Go协程的基本原理.同步机制.高级用法及其性能与最佳实践,旨在为读者提供全面.深入的理解和应用指 ...

  5. 【爬虫笔记】Python爬虫简单运用爬取代理IP

    一.前言 近些年来,网络上的爬虫越来越多,很多网站都针对爬虫进行了限制,封禁了一些不规则的请求.为了实现正常的网络爬虫任务,爬虫常用代理IP来隐藏自己的真实IP,避免被服务器封禁.本文将介绍如何使用P ...

  6. torch.nn.ReLU(inplace=True)的具体含义:

    首先根据源文档中的ReLU(x)=max(0,x),得出结论.大于0的数值不变,小于0的数据变成0. 补充:这里需要注意的是 ReLU并没有限制数据的大小. 这是对应的文档链接:https://pyt ...

  7. PHP-basename

    basename 定义: basename() 函数返回路径中的文件名部分. 语法: basename(path,suffix) 参数 描述 path 必需.规定要检查的路径 suffix 可选.规定 ...

  8. Qt信号槽与事件循环学习笔记

    事件与事件循环 信号槽机制 事件与事件循环 在Qt中,事件(event)被封装为QEvent类/子类对象,用来表示应用内部或外部发生的各种事情.事件可以被任何QObject子类的对象接收并处理. 根据 ...

  9. 【PHP反序列化】速览

    PHP反序列化 一.原理 序列化就是将对象转化成字符串,反序列化相反.数据的格式转换和对象的序列化有利于对象的保存 . 反序列化漏洞:就是php对数据进行反序列化时,没有进行过滤,导致用户可以控制反序 ...

  10. 2D物理引擎 Box2D for javascript Games 第五章 碰撞处理

    2D物理引擎 Box2D for javascript Games 第五章 碰撞处理 碰撞处理 考虑到 Box2D 世界和在世界中移动的刚体之间迟早会发生碰撞. 而物理游戏的大多数功能则依赖于碰撞.在 ...