前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CompletableFuture的使用与原理解析

CompletableFuture的使用与原理解析

原创
作者头像
Kokomo
发布2023-11-27 14:18:25
2030
发布2023-11-27 14:18:25
举报
文章被收录于专栏:灵墨AI探索室灵墨AI探索室

1 简介

CompletableFuture 是 JDK8 中新增的多线程任务执行类,通过它我们可以方便地进行串行、并行、组合和转换异步任务。它能够以一种非常灵活的方式处理异步操作的结果,包括成功的结果、异常和取消等情况。接下来,我们就详细了解一下这个类。

2 具体方法及使用

在正常的业务代码开发中,如果我们需要使用子线程处理数据通常需要使用线程池,但手动创建线程池很麻烦,而且还需要注意销毁。在 JDK8 中 CompletableFuture就很好的替我们解决了这个问题。下面我们来看一下如何使用这个类。

实例化

代码语言:javascript
复制
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);

supplyAsync和runAsync区别在于supplyAsync会返回一个CompletableFuture对象,而runAsync不会,此外在进行实例化时可以指定线程池

代码语言:javascript
复制
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {    // 执行具有返回值的任务    return "灵墨AI探索室";});CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {    // 执行没有返回值的任务});
ExecutorService customExecutor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {   return "灵墨AI探索室";}, customExecutor);

获取结果

代码语言:javascript
复制
public T    get()
public T    get(long timeout, TimeUnit unit)
public T    getNow(T valueIfAbsent)
public T    join()

get和join方法都是阻塞当前线程,直到获取接口 但join方法不会显式的抛出异常,更适合在流式编程中使用,get方法还可以指定等待时间,超时抛出异常。

代码语言:javascript
复制
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {   
 // 执行具有返回值的任务    
 return "灵墨AI探索室";});
 future.get();
 //需处理异常
future.join();
future.get(1, TimeUnit.MINUTES);//get方法可以指定等待时间

下一步处理

代码语言:javascript
复制
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
public CompletableFuture<Void> thenAccept(Consumer<? super T> action);
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);

这几个方法都是用来在CompletableFuture完成后进行下一步处理,这里使用thenApply举一个例子

代码语言:javascript
复制
CompletableFuture<Score> future = CompletableFuture.supplyAsync(() -> {   
        // 获取学生信息           
 return StudentService.getStudent(id);       
  }).thenApply(student -> {   
           // 再根据学生信息获取考试分数          
    return ScoreServcie.getScore(student);      
 });

异常处理

代码语言:javascript
复制
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)

这两个方法是用来处理CompletableFuture执行过程中的异常。

此外CompletableFuture还提供了anyOf,allOf等方法用来统一对多个任务进行处理。

相信各位小伙伴看到这里已经对CompletableFuture有了大致的了解,上面列举的方法不算全面,但已经能够覆盖开发中的大部分场景了,下面我们就详细了解一下CompletableFuture的内部结构。

3 实现原理

我们先看一下CompletableFuture 的类图关系 它继承了Future和CompletionStage两个类

图片
图片

在CompletableFuture 中有两个属性值值得关注

代码语言:javascript
复制
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {  
  volatile Object result;           
  volatile Completion stack;   
 }

其中result 用来保存future的结果,stack是利用链表实现的栈,记录了这个future的后续动作,在使用CompletableFuture 时,每次调用都会生成一个新的CompletableFuture 这些future就是通过stack记录的信息串联起来的,我们来举一个例子

代码语言:javascript
复制
CompletableFuture.supplyAsync(() -> 10).thenApply(i -> i + 10).thenApply(i -> i + 20);

在这行代码中 各CompletableFuture 对象的结构如下图表示。

图片
图片

有些同学看到这里可能有些疑惑,这种结构为什么不直接使用一个指针,而是使用栈。这是因为CompletableFuture 同时支持多个后续任务。

同步任务和异步任务

在CompletableFuture 中提供的几乎每一个同步方法都会对应提供一个异步方法,从接口名上就很容易分辨,比如下面这几个

thenRun

thenRunAsync

thenAccept

thenRunAsync

thenApply

thenApplyAsync

此处需要注意的是,异步任务在任何情况下都会在线程池中运行,而同步任务的前置任务如果是异步任务,同步任务也会在线程池中运行

图片
图片

图中的蓝色的是异步任务 黄色的是同步任务,而由于2的前置任务1是异步任务,所以2、3和1都会在同一个异步线程中执行,4、5也同理 只不过由于4是异步任务导致4、5和1、2、3不在同一个线程中。

此外,2、3是同步任务 所有2、3是在同一个线程中按照出栈顺序执行的,如果2、3变为异步任务,则执行顺序是不固定的。

CompletableFuture 在使用起来十分便捷,但也要注意,由于服务器的cpu核数是有限的,如果使用异步的地方过多,最终也会导致阻塞,各位小伙伴在使用时也多加注意,希望各位小伙伴能点个关注,这对我们是一种很大的鼓励。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档