深入解析CompletableFuture的功能和用法

简介: 1. CompletableFuture 简介1.1 概述CompletableFuture是 Java 8 中引入的一个类,它实现了CompletionStage接口,提供了一组丰富的方法来处理异步操作和多个任务的结果。它支持链式操作,可以方便地处理任务的依赖关系和结果转换。相比于传统的Future接口,CompletableFuture更加灵活和强大。

1. CompletableFuture 简介

1.1 概述

CompletableFuture是 Java 8 中引入的一个类,它实现了CompletionStage接口,提供了一组丰富的方法来处理异步操作和多个任务的结果。它支持链式操作,可以方便地处理任务的依赖关系和结果转换。相比于传统的Future接口,CompletableFuture更加灵活和强大。

1.2 优势与特点

CompletableFuture的使用具有以下优势和特点:

  • 异步执行:CompletableFuture允许任务在后台线程中异步执行,不会阻塞主线程,提高了应用程序的响应性和性能。
  • 链式操作:通过CompletableFuture提供的方法,可以方便地对任务进行链式操作,构建复杂的任务依赖关系,实现高效的任务调度和执行。
  • 异常处理:CompletableFuture提供了丰富的异常处理方法,可以处理任务执行过程中可能发生的异常,并实现灵活的错误处理和回退机制。
  • 多任务组合:CompletableFuture支持多个任务的并发执行和结果组合。可以轻松地实现多任务并发处理的场景,提高应用程序的效率和并发性。

2. CompletableFuture 的基本用法

2.1 创建 CompletableFuture 对象

使用CompletableFuture创建异步任务非常简单。可以使用
CompletableFuture.supplyAsync()

CompletableFuture.runAsync()
方法来创建CompletableFuture对象。

2.1.1 使用CompletableFuture.supplyAsync() 方法

使用
CompletableFuture.supplyAsync()
方法来创建 CompletableFuture 对象的示例。该方法用于执行具有返回值的任务,并在任务完成时返回结果。

arduino复制代码CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行具有返回值的任务
    return "任务结果";
});

在上述示例中,我们使用
CompletableFuture.supplyAsync()
方法创建一个具有返回值的 CompletableFuture 对象,任务会在默认的 ForkJoinPool 中异步执行。

2.1.2 使用CompletableFuture.runAsync() 方法

除了
CompletableFuture.supplyAsync()
方法,CompletableFuture 还提供了
CompletableFuture.runAsync()
方法用于执行没有返回值的任务。

java复制代码CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    // 执行没有返回值的任务
});

在上述示例中,我们使用
CompletableFuture.runAsync()
方法创建一个没有返回值的 CompletableFuture 对象,任务会在默认的 ForkJoinPool 中异步执行。

2.1.3 指定自定义线程池

我们还可以通过指定自定义线程池来创建 CompletableFuture 对象,以满足特定的并发需求。

java复制代码ExecutorService customExecutor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行任务的代码
}, customExecutor);

在上述示例中,我们通过
Executors.newFixedThreadPool(10)
创建了一个固定大小为 10 的自定义线程池,并将其传递给
CompletableFuture.supplyAsync()
方法来执行异步任务。

2.2 获取任务结果

获取CompletableFuture任务的结果有多种方式。最常用的方式是使用join() 方法阻塞当前线程,直到任务完成并返回结果。

2.2.1 使用join() 方法

join() 方法是 CompletableFuture 类提供的一种获取任务结果的方式,它会阻塞当前线程,直到任务完成并返回结果。

java复制代码CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行任务的代码
    return "任务结果";
});
String result = future.join();

在上述示例中,我们使用join() 方法获取任务的结果,并将结果赋值给result变量。如果任务还未完成,join() 方法会阻塞当前线程,直到任务完成。

join() 方法和get() 方法非常相似,但join() 方法不会抛出InterruptedExceptionExecutionException异常,而是将异常包装在CompletionException中抛出。因此,它更适合在 Lambda 表达式或流式操作中使用。

2.2.2 使用get() 方法

get() 方法也是 CompletableFuture 类提供的一种获取任务结果的方式,它会阻塞当前线程,直到任务完成并返回结果。与join() 方法不同的是,get() 方法会抛出InterruptedExceptionExecutionException异常,需要进行异常处理。

java复制代码CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行任务的代码
    return "任务结果";
});
try {
    String result = future.get();
} catch (InterruptedException | ExecutionException e) {
    // 异常处理逻辑
}

在上述示例中,我们使用get() 方法获取任务的结果,并在可能抛出异常的情况下进行异常处理。如果任务还未完成,get() 方法会阻塞当前线程,直到任务完成。

get() 方法的异常处理较为繁琐,需要捕获InterruptedExceptionExecutionException异常,并进行相应的处理。因此,在 Lambda 表达式或流式操作中,推荐使用join() 方法。

2.3 异步回调方法

CompletableFuture 提供了一系列方法来处理任务的完成事件,实现异步回调。我们将逐一介绍这些方法的区别和用法。

thenApply()

方法签名:thenApply(Function fn)

  • 输入参数:上一阶段的任务结果类型为 T。
  • 返回值:新阶段的任务结果类型为 U。
  • 功能:对上一阶段的任务结果进行转换操作,并返回一个新的 CompletableFuture 对象。
java复制代码CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 42)
    .thenApply(result -> result * 2)
    .thenApply(result -> result + 1);

在上述示例中,我们使用 thenApply()方法对上一阶段的结果进行转换,将结果乘以 2,并将转换后的结果加 1。每个 thenApply()方法都返回一个新的 CompletableFuture 对象,可以继续链式调用。

thenAccept()

方法签名:thenAccept(Consumer action)

  • 输入参数:上一阶段的任务结果类型为 T。
  • 返回值:CompletableFuture,没有返回值。
  • 功能:对上一阶段的任务结果进行消费操作,没有返回值。
java复制代码CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 42)
    .thenAccept(result -> System.out.println("任务结果:" + result));

在上述示例中,我们使用 thenAccept()方法对上一阶段的结果进行消费,将结果打印输出。thenAccept()方法没有返回值,仅用于消费任务结果。

thenRun()

方法签名:thenRun(Runnable action)

  • 输入参数:无。
  • 返回值:CompletableFuture,没有返回值。
  • 功能:在上一阶段任务完成后执行给定的 Runnable 任务,没有输入参数和返回值。
java复制代码CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 42)
    .thenRun(() -> System.out.println("任务执行完毕"));

在上述示例中,我们使用 thenRun()方法在上一阶段任务完成后执行一个 Runnable 任务,输出一条任务执行完毕的消息。

2.4 多任务组合回调

CompletableFuture 还提供了一些方法来组合多个任务的结果,实现更复杂的异步处理逻辑。

thenCombine()

方法签名:thenCombine(CompletionStage other, BiFunction fn)

  • 输入参数:另一个 CompletionStage 对象和一个 BiFunction 函数,函数的输入参数分别为上一阶段的任务结果类型 T 和另一个 CompletionStage 对象的任务结果类型 U,函数的返回值类型为 V。
  • 返回值:新阶段的任务结果类型为 V。
  • 功能:当两个 CompletionStage 对象都完成时,将它们的任务结果传递给给定的 BiFunction 函数进行组合处理,并返回一个新的 CompletableFuture 对象。
java复制代码CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<Integer> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + result2);

在上述示例中,我们使用 thenCombine()方法将两个任务的结果进行组合,将它们的结果相加并返回新的 CompletableFuture 对象。

thenCompose()

方法签名:thenCompose(Function fn)

  • 输入参数:一个 Function 函数,函数的输入参数为上一阶段的任务结果类型 T,函数的返回值为另一个 CompletionStage 对象。
  • 返回值:新阶段的任务结果类型为 U。
  • 功能:当上一阶段的任务完成后,将结果传递给给定的 Function 函数,该函数返回一个新的 CompletionStage 对象,新阶段的任务结果类型为 U。
java复制代码CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = future1.thenCompose(result -> CompletableFuture.supplyAsync(() -> result * 2));

在上述示例中,我们使用 thenCompose()方法将上一阶段的结果传递给一个 Function 函数,该函数返回一个新的 CompletionStage 对象。新阶段的任务结果为上一阶段结果的两倍。

allOf()

方法签名:allOf(CompletableFuture... cfs)

  • 输入参数:多个 CompletableFuture 对象。
  • 返回值:CompletableFuture,没有返回值。
  • 功能:等待所有给定的 CompletableFuture 对象都完成,返回一个新的 CompletableFuture 对象。
java复制代码CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);

在上述示例中,我们使用 allOf()方法等待所有的 CompletableFuture 对象都完成,返回一个新的 CompletableFuture 对象。这样我们就可以在该对象上进行进一步的处理,例如获取各个 CompletableFuture 的结果。

3. 异常处理与错误处理

3.1 异常处理方法

CompletableFuture 提供了多种方法来处理异步任务执行中可能发生的异常。常用的方法有:

  • exceptionally(Function fn) :当 CompletableFuture 执行过程中发生异常时,使用指定的函数进行异常处理,并返回一个新的 CompletableFuture 对象,其中包含处理结果或默认值。
java复制代码CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    throw new RuntimeException("任务执行异常");
});
CompletableFuture<Integer> handledFuture = future.exceptionally(ex -> {
    System.out.println("异常处理:" + ex.getMessage());
    return 0; // 默认值
});
  • handle(BiFunction fn) :当 CompletableFuture 执行完成时,使用指定的函数处理结果或异常,并返回一个新的 CompletableFuture 对象。
java复制代码CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 42);
CompletableFuture<String> handledFuture = future.handle((result, ex) -> {
    if (ex != null) {
        System.out.println("异常处理:" + ex.getMessage());
        return "默认值";
    } else {
        return "结果:" + result;
    }
});

3.2 错误处理与异常链

CompletableFuture 还支持异常链,可以将多个 CompletableFuture 的异常连接起来,形成异常链。可以使用exceptionally()handle() 方法来实现异常链的处理。

java复制代码CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    throw new RuntimeException("任务执行异常");
});
CompletableFuture<Integer> handledFuture = future.exceptionally(ex -> {
    System.out.println("异常处理:" + ex.getMessage());
    throw new CustomException("自定义异常", ex);
});

在上述示例中,我们通过exceptionally() 方法处理任务的异常,并抛出一个自定义异常,并将原始异常作为异常链的一部分传递下去。

4. 自定义线程池与资源管理

4.1 默认线程池与 ForkJoinPool

CompletableFuture 默认使用 ForkJoinPool 线程池来执行异步任务。ForkJoinPool 是一种基于工作窃取算法的线程池,适用于任务分解和并行计算。

java复制代码CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 异步任务的代码
});

在上述代码中,CompletableFuture 会在默认的 ForkJoinPool 中异步执行任务。

4.2 自定义线程池

除了使用默认线程池,我们还可以自定义线程池来满足特定的需求。自定义线程池可以通过Executors类来创建。

java复制代码ExecutorService customExecutor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 异步任务的代码
}, customExecutor);

在上述代码中,我们创建了一个固定大小为 10 的自定义线程池,并将其传递给 CompletableFuture 来执行异步任务。

4.3 资源管理与关闭线程池

在使用自定义线程池时,需要注意及时关闭线程池以释放资源。可以使用ExecutorServiceshutdown()shutdownNow() 方法来关闭线程池。

java复制代码ExecutorService customExecutor = Executors.newFixedThreadPool(10);
// 异步任务代码
customExecutor.shutdown();

在上述代码中,我们在任务完成后调用了shutdown() 方法来关闭线程池。

5. 并发任务的调度与控制

5.1 异步任务的并发度控制

CompletableFuture 允许我们控制并发任务的执行数量。可以通过自定义线程池的大小来限制并发度。

java复制代码ExecutorService customExecutor = Executors.newFixedThreadPool(5);
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 异步任务1的代码
}, customExecutor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 异步任务2的代码
}, customExecutor);
// ...

在上述代码中,我们通过自定义线程池的大小为 5 来限制并发任务的数量。

5.2 任务的超时处理

CompletableFuture 还提供了超时处理的功能,可以控制任务的最大执行时间。可以使用completeOnTimeout() 方法来实现超时处理。

java复制代码CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 异步任务的代码
}).completeOnTimeout("默认值", 5, TimeUnit.SECONDS);

在上述代码中,我们指定任务的最大执行时间为 5 秒,如果任务在规定时间内没有完成,将返回默认值。

5.3 中断与取消任务

在某些情况下,我们可能需要中断或取消正在执行的任务。CompletableFuture 提供了cancel() 方法来取消任务的执行。

java复制代码CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 异步任务的代码
});
boolean canceled = future.cancel(true);

在上述代码中,我们调用cancel() 方法来取消任务的执行,并传递一个布尔值表示是否中断正在执行的任务。

6. CompletableFuture 的进阶应用

6.1 CompletableFuture 与 IO 操作

CompletableFuture 在处理 IO 操作时非常有用。可以将 IO 操作封装为 CompletableFuture 任务,利用 CompletableFuture 的异步特性提高 IO 操作的效率。

java复制代码CompletableFuture<String> readData = CompletableFuture.supplyAsync(() -> {
    // 执行读取数据的IO操作
    return "读取的数据";
});
CompletableFuture<Void> processData = readData.thenAccept(data -> {
    // 处理读取到的数据
    System.out.println("读取到的数据:" + data);
    // 执行处理数据的操作
});
CompletableFuture<Void> writeData = processData.thenRun(() -> {
    // 执行写入数据的IO操作
    System.out.println("数据写入完成");
});
writeData.join();

在上述代码中,我们使用 CompletableFuture 处理了一个包含读取数据、处理数据和写入数据的 IO 操作流程。通过异步执行和链式操作,可以有效地利用 CPU 和 IO 资源,提高程序的响应性和吞吐量。

6.2 CompletableFuture 与网络请求

CompletableFuture 也可以很好地与网络请求结合使用。我们可以使用 CompletableFuture 发起多个网络请求,并在所有请求完成后处理结果。

java复制代码CompletableFuture<String> request1 = CompletableFuture.supplyAsync(() -> {
    // 发起网络请求1
    return "请求1结果";
});
CompletableFuture<String> request2 = CompletableFuture.supplyAsync(() -> {
    // 发起网络请求2
    return "请求2结果";
});
CompletableFuture<String> request3 = CompletableFuture.supplyAsync(() -> {
    // 发起网络请求3
    return "请求3结果";
});
CompletableFuture<Void> allRequests = CompletableFuture.allOf(request1, request2, request3);
allRequests.thenRun(() -> {
    // 所有请求完成后的处理逻辑
    String result1 = request1.join();
    String result2 = request2.join();
    String result3 = request3.join();
    // 对请求结果进行处理
});

在上述代码中,我们使用 CompletableFuture 发起了三个网络请求,并通过allOf() 方法等待所有请求完成。在所有请求完成后,我们可以使用join() 方法获取各个请求的结果,并进行后续处理。

7. 实战案例

业务背景: 在电商项目的售后业务中,当客服接收到用户的售后申请时,需要进行一系列操作,包括查询订单信息、查询 ERP 中的商品信息、查询用户信息,以及创建售后工单。

代码实现:

java复制代码public CompletableFuture<Void> processAfterSalesRequest(String orderId, String customerId) {
    CompletableFuture<Order> orderFuture = CompletableFuture.supplyAsync(() -> getOrderInfo(orderId));
    CompletableFuture<Inventory> inventoryFuture = CompletableFuture.supplyAsync(() -> getInventoryInfo(orderId));
    CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(() -> getUserInfo(customerId));
    return CompletableFuture.allOf(orderFuture, inventoryFuture, userFuture)
        .thenApplyAsync(ignored -> {
            Order order = orderFuture.join();
            Inventory inventory = inventoryFuture.join();
            User user = userFuture.join();
            // 创建售后工单
            createAfterSalesTicket(order, inventory, user);
            return null;
        });
}
private Order getOrderInfo(String orderId) {
    // 查询订单信息的逻辑
    // ...
    return order;
}
private Inventory getInventoryInfo(String orderId) {
    // 查询ERP中商品信息的逻辑
    // ...
    return inventory;
}
private User getUserInfo(String customerId) {
    // 查询用户信息的逻辑
    // ...
    return user;
}
private void createAfterSalesTicket(Order order, Inventory inventory, User user) {
    // 创建售后工单的逻辑
    // ...
}

在上述代码中,我们使用
CompletableFuture.supplyAsync()
方法分别查询订单信息、ERP 中的商品信息和用户信息,然后使用CompletableFuture.allOf() 方法等待所有查询任务完成。完成后,我们可以通过join() 方法获取各个查询任务的结果,并将结果传递给createAfterSalesTicket() 方法来创建售后工单。

8. 总结

CompletableFuture 是提供了丰富的功能和方法。它能简化并发任务处理,提高系统性能和响应性。通过了解其基本用法、进阶应用和最佳实践,我们可以灵活处理异步回调、任务组合、异常处理和资源管理。

相关文章
|
7月前
|
人工智能 监控 算法
销售易CRM:功能与优势全解析
销售易CRM是国内领先的客户关系管理(CRM)系统,提供强大的销售管理、全方位客户管理、丰富的营销自动化工具、智能AI赋能及灵活的开放性平台。其功能涵盖线索获取、商机管理、客户画像、营销活动策划、智能预测等,支持企业高效管理客户、优化业务流程、提升销售效率和客户满意度。通过灵活的二次开发和API接口,销售易CRM可无缝集成企业现有系统,助力企业在数字化转型中实现业绩高质量增长。
|
7月前
|
弹性计算 运维 安全
优化管理与服务:操作系统控制平台的订阅功能解析
本文介绍了如何通过操作系统控制平台提升系统效率,优化资源利用。首先,通过阿里云官方平台开通服务并安装SysOM组件,体验操作系统控制平台的功能。接着,详细讲解了订阅管理功能,包括创建订阅、查看和管理ECS实例的私有YUM仓库权限。订阅私有YUM仓库能够集中管理软件包版本、提升安全性,并提供灵活的配置选项。最后总结指出,使用阿里云的订阅和私有YUM仓库功能,可以提高系统可靠性和运维效率,确保业务顺畅运行。
|
6月前
|
存储 前端开发 JavaScript
调用DeepSeek API增强版纯前端实现方案,支持文件上传和内容解析功能
本方案基于DeepSeek API增强版,提供纯前端实现的文件上传与内容解析功能。通过HTML和JavaScript,用户可选择文件并调用API完成上传及解析操作。方案支持多种文件格式(如PDF、TXT、DOCX),具备简化架构、提高响应速度和增强安全性等优势。示例代码展示了文件上传、内容解析及结果展示的完整流程,适合快速构建高效Web应用。开发者可根据需求扩展功能,满足多样化场景要求。
2195 64
|
7月前
|
人工智能 API 语音技术
HarmonyOS Next~鸿蒙AI功能开发:Core Speech Kit与Core Vision Kit的技术解析与实践
本文深入解析鸿蒙操作系统(HarmonyOS)中的Core Speech Kit与Core Vision Kit,探讨其在AI功能开发中的核心能力与实践方法。Core Speech Kit聚焦语音交互,提供语音识别、合成等功能,支持多场景应用;Core Vision Kit专注视觉处理,涵盖人脸检测、OCR等技术。文章还分析了两者的协同应用及生态发展趋势,展望未来AI技术与鸿蒙系统结合带来的智能交互新阶段。
419 31
|
7月前
|
供应链 监控 搜索推荐
反向海淘代购独立站:功能解析与搭建指南
“反向海淘”指海外消费者购买中国商品的现象,体现了中国制造的创新与强大。国产商品凭借高性价比和丰富功能,在全球市场备受欢迎。跨境电商平台的兴起为“反向海淘”提供了桥梁,而独立站因其自主权和品牌溢价能力逐渐成为趋势。一个成功的反向海淘代购独立站需具备多语言支持、多币种支付、物流跟踪、商品展示、购物车管理等功能,并通过SEO优化、社交媒体营销等手段提升运营效果。这不仅助力中国企业开拓海外市场,还推动了品牌全球化进程。
207 19
|
7月前
|
SQL 运维 监控
高效定位 Go 应用问题:Go 可观测性功能深度解析
为进一步赋能用户在复杂场景下快速定位与解决问题,我们结合近期发布的一系列全新功能,精心梳理了一套从接入到问题发现、再到问题排查与精准定位的最佳实践指南。
|
7月前
|
算法 前端开发 定位技术
地铁站内导航系统解决方案:技术架构与核心功能设计解析
本文旨在分享一套地铁站内导航系统技术方案,通过蓝牙Beacon技术与AI算法的结合,解决传统导航定位不准确、路径规划不合理等问题,提升乘客出行体验,同时为地铁运营商提供数据支持与增值服务。 如需获取校地铁站内智能导航系统方案文档可前往文章最下方获取,如有项目合作及技术交流欢迎私信我们哦~
428 1
|
7月前
|
JSON 自然语言处理 前端开发
WebSocket调试工具深度对比:Postman与Apipost功能实测解析
本文深入对比了Postman与Apipost两款WebSocket调试工具。作为实时通讯系统工程师,作者在开发智能客服系统时遇到了传统工具调试复杂、文档管理不便的问题。通过引入Apipost的智能连接池、消息分组管理和自动化文档生成等功能,实现了多环境自动切换、消息分类和接口文档自动生成,极大提升了调试效率和团队协作效果。最终,使用Apipost使接口调试时间减少40%,文档维护成本降低70%,跨团队沟通效率提升50%。
|
7月前
|
人工智能 搜索推荐 数据挖掘
销售易CRM:功能与优势全解析
销售易CRM是国内领先的客户关系管理系统,提供从线索获取到订单成交的完整销售漏斗管理,涵盖销售、客户、营销管理和AI赋能等功能。其强大的销售管理功能包括线索与商机管理、销售预测等;全方位客户管理实现360度客户视图;丰富的营销自动化工具支持多渠道营销活动;智能AI技术提升销售效率和客户满意度;灵活的开放性平台满足定制化需求;现代化界面设计简洁直观,支持多设备访问;移动端功能齐全,协同工具丰富;优质的客户服务确保快速响应和技术支持。销售易CRM助力企业优化业务流程,推动销售增长。
|
7月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。

推荐镜像

更多
  • DNS