前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >还在用Future搞异步?快看看企业中常用的CompletableFuture是怎么用的!

还在用Future搞异步?快看看企业中常用的CompletableFuture是怎么用的!

作者头像
程序员牛肉
发布2024-11-21 19:47:40
发布2024-11-21 19:47:40
11300
代码可运行
举报
运行总次数:0
代码可运行

大家好,我是程序员牛肉。

不知道你们在使用多线程的时候会用什么方式来获取异步结果?大多数人接触的首个方法肯定是使用Future来获取异步结果。

让我们先看一下一整个Future的结构图

[Future 是 Java 并发包(java.util.concurrent)中的一个接口,用于表示一个异步计算的结果。它提供了一种机制,可以在异步任务完成后获取结果或处理异常。]

使用Future的方法很简单,如下图所示:

代码语言:javascript
代码运行次数:0
复制
 List<Future<Void>> futures = new ArrayList<>();
    for (OrderDTO order : ListResponse.getOrders(){
          futures.add(threadPool.submit(() -> {
           itemList.add(order);
            return null;}));
    }

这样的话,我们就可以获取所有执行任务线程的Future对象,通过这个对象,我们可以对执行任务的线程进行一些操作:

  1. 获取任务结果:
    • 使用 get() 方法可以获取任务的执行结果。如果任务尚未完成,get() 会阻塞当前线程,直到任务完成并返回结果。
    • get(long timeout, TimeUnit unit) 方法允许设置超时时间,如果在指定时间内任务未完成,则会抛出 TimeoutException。
  2. 取消任务:
    • 使用 cancel(boolean mayInterruptIfRunning) 方法尝试取消任务。参数 mayInterruptIfRunning 表示是否允许中断正在执行的任务。
    • 任务能否被取消取决于任务的状态以及是否支持取消操作。
  3. 检查任务状态:
    • isDone() 方法用于检查任务是否已经完成。
    • isCancelled() 方法用于检查任务是否在完成前被取消。

虽然基于Future我们对线程有了更加高的操作自由,但它也有自己的缺点。

1.Future接口中没有关于异常处理的方法,这对于我们的项目开发来讲是一个很憋屈的点。使用Future的时候需要我们在任务执行时捕获异常,然后将异常封装到 Future 对象中返回。

2.Future的不支持组合多个异步任务的结果,如果要处理多个异步任务之间的依赖或者组合,需要我们手动完成。

这么明显的缺点我们都能发现,那么更不要提那些维护Java的核心开发者了。

于是Java8狠活来袭,Java核心开发者引入了Completablefuture来解决我们上述提到的这两个问题。

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html 对应的官方文档

而我们这一篇主要介绍一下Completablefuture类中的常用方法。

1.runAsync: 执行异步计算,但是不会返回结果。该方法接受一个Runnable对象并且返回一个CompletableFuture<Void>。

代码语言:javascript
代码运行次数:0
复制
  CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
     try {
          System.out.println("Task is running in a separate thread: " + Thread.currentThread().getName());
          Thread.sleep(2000); // 模拟耗时操作
       } catch (InterruptedException e) {
                throw new IllegalStateException(e);
      }
            System.out.println("Task completed!");
        });    

2.supplyAsync: 执行异步计算,并返回结果。

代码语言:javascript
代码运行次数:0
复制
       CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 任务内容:模拟长时间运行的任务
            try {
                System.out.println("Task is running in a separate thread: " + Thread.currentThread().getName());
                Thread.sleep(2000); // 模拟耗时操作
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Task completed!";
        });

3.thenApply :thenApply 方法用于在 CompletableFuture 完成后,对其结果进行转换或处理,并返回一个新的 CompletableFuture。

代码语言:javascript
代码运行次数:0
复制
public <U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn)

代码实例:

代码语言:javascript
代码运行次数:0
复制
public class CompletableFutureThenApplyExample {
    public static void main(String[] args) {
        // 创建一个异步任务,返回一个整数
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("Calculating... in thread: " + Thread.currentThread().getName());
            return 42; // 模拟一个计算结果
        });

        // 使用 thenApply 对结果进行转换,将整数转换为字符串
        CompletableFuture<String> stringFuture = future.thenApply(result -> {
            System.out.println("Transforming result in thread: " + Thread.currentThread().getName());
            return "The answer is " + (result+1);
        });
        }
    }
}

基于thenApply,我们实现了对CompletableFuture的结果进行的二次处理。需要注意的是thenApply在执行的时候,使用的是执行CompletableFuture的线程。

既然有这种两个任务是同一个线程处理的,那就有两个任务不是同一个线程处理的方法,它的名字叫做thenApplyAsync。

对比thenApplyAsync和thenApply的源码,会发现thenApplyAsync只不过是在提交参数的时候多提交了一个线程池。

4.thenAccept thenAccept 方法用于在 CompletableFuture 完成后,对其结果进行转换或处理。这个方法只消费,没有返回值。

代码例子就不举了,有点水字数的嫌疑了,参考看一下thenApply的代码就好了。

同理thenAccept在处理时使用的也是执行CompletableFuture的线程。而如果想要新开一个线程来处理thenAccept方法的话,可以使thenApplyAsync。

5.CompletableFuture.allOf() : 他是一个静态方法,用于组合多个方法,当所有的Completablefuture方法都完成的时候,返回的 CompletableFuture<Void> 也将完成。这在需要等待多个并发任务全部完成时非常有用。

代码语言:javascript
代码运行次数:0
复制
    public static void main(String[] args) {
        CompletableFuture<Void> allOfFutures = CompletableFuture.allOf(future1, future2);
        allOfFutures.thenRun(() -> System.out.println("All tasks completed"));
    }

6.CompletableFuture.anyOf:等待任意一个给定的 CompletableFuture 完成。

代码语言:javascript
代码运行次数:0
复制
    public static void main(String[] args) {
        CompletableFuture<Object> anyOfFutures = CompletableFuture.anyOf(future1, future2);
        anyOfFutures.thenAccept(result -> System.out.println("First completed task result: " + result));
    }

除此之外还有CompletableFuture还有一些方法没有被介绍,但这些内容一问GPT就知道了,没必要在这里赘述。

今天关于CompletableFuture的介绍就到这里了,本篇也主要是向大家介绍这么一个异步工具类去使用,不涉及底层原理。希望我的文章可以帮到你。

对于CompletableFuture你有什么想说的嘛?欢迎在评论区留言。

关注我,带你了解更多计算机干货。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员牛肉 微信公众号,前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

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