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. 《SQL与数据库基础》11. 索引

    目录 索引 概述 结构 B-Tree B+Tree Hash 思考 分类 语法 SQL性能分析 SQL执行频率 慢查询日志 profile详情 explain执行计划 索引失效情况 范围查询 索引列运 ...

  2. .NET Core WebAPI 基础 文件上传

    昨天分享了一个在WebApi中如何接收参数的文章 .NET API 中的 FromRoute.FromQuery.FromBody 用法 - 一事冇诚 - 博客园 (cnblogs.com),然后有新 ...

  3. AI测试,给出的答案还挺那么回事儿的~

    今天文心一言全民开放了,所有人都可以正常下载使用了,不用像之前一样排队等号了.之前内测阶段倒也体验过,技术人员总是喜欢尝鲜,第一时间拿到邀请码后就各种调戏了TA一番,那时觉得给出的答案总有些差强人意, ...

  4. 单节点 RAID6 可靠性模型

    介绍 独立磁盘冗余阵列(Redundant Arrays of Independent Disks, RAID)是存储业界为保证数据可用性.可靠性和完整性所采用的重要技术,即使在分布式多副本如此流行和 ...

  5. 二叉搜索树(Binary Search Tree,BST)

    二叉搜索树(Binary Search Tree,BST) 二叉搜索树(Binary Search Tree),也称二叉查找树或二叉排序树,是一种特殊的二叉树,它满足以下性质 对于二叉搜索树的每个节点 ...

  6. Aho-Corasick 算法 AC自动机实现

    敏感词过滤在社区发帖.网站检索.短信发送等场景下是很常见的需求,尤其是在高并发场景下如何实现敏感词过滤,都对过滤算法提出了更高的性能要求,Ahocorasick算法能够实现毫秒级的万字过滤匹配,能够很 ...

  7. 如何选择适合你的HTAP数据库?

    最近,在数据库行业对HTAP(混合事务/分析处理,Hybrid Transactional/Analytical Processing)这个概念宣传的非常火爆,也衍生出 Real-Time HTAP的 ...

  8. 将python程序打包为exe可执行文件方法

    将py打包为exe文件需要依赖pyinstaller第三方库 -F:打包后只生成单个exe格式文件: -D:默认选项,创建一个目录,包含exe文件以及大量依赖文件: -c:默认选项,使用控制台(就是类 ...

  9. EMC ndmp NAS

    NAS 是带存储系统的专用高性能文件服务器.它可提供文件级数据访问和共享. NAS 使用网络和文件共享协议,包括用于数据传输的 TCP/IP 以及用于远程文件服务的 CIFS 和 NFS. 最简单的备 ...

  10. 造轮子之集成GraphQL

    先简单对比以下GraphQL和WebAPI:GraphQL和Web API(如RESTful API)是用于构建和提供Web服务的不同技术. 数据获取方式: Web API:通常使用RESTful A ...