CompletableFuture 是 Java 8 引入的一个类,用于支持异步编程和非阻塞操作。它提供了一种简单而强大的方式来处理异步任务,可以轻松地实现并行、非阻塞的操作,并且提供了丰富的方法来处理任务的完成状态、异常情况以及多个任务之间的串联和组合。
我将使用CompletableFuture
的以下API来说明CompletableFuture
的使用方法。
public class CompletableFutureExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 异步任务启动:supplyAsync
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1开始执行");
try {
//模拟执行耗时操作
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return 100;
});
// 异步任务结果处理:thenApply
CompletableFuture<String> result1 = future1.thenApply(value -> {
System.out.println("任务1结果处理: " + value);
return "Processed Result1: " + value;
});
// 串联/组合多个任务的处理结果:exceptionally
CompletableFuture<String> result2 = result1.exceptionally(ex -> "任务1出现异常: " + ex.getMessage());
// 超时处理:orTimeout
CompletableFuture<String> result3 = CompletableFuture.supplyAsync(() -> {
try {
//模拟执行耗时操作
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "任务2完成";
}).orTimeout(2, TimeUnit.MINUTES);
// 流处理/函数式编程:与 Stream 接口结合
CompletableFuture<Void> result4 = CompletableFuture.runAsync(() -> {
System.out.println("任务3开始执行");
});
// 等待所有任务完成
CompletableFuture.allOf(result2, result3, result4).join();
System.out.println(result2.get());
System.out.println(result3.get());
}
}
假如你是一名高级高级工程师,你们项目组正在做电商相关的业务,对接口的响应速度要求较高,现在有个需求是需要同时查询出:用户的账号信息、订单信息、购物车信息、银行卡支付信息,如果没有并发思想,那么接口的视线逻辑大致是这样的:
public class ECommerceService {
public UserAccount getUserAccount() {
// 执行查询用户账号信息的逻辑
UserAccount userAccount = // ...;
return userAccount;
}
public OrderInfo getOrderInfo() {
// 执行查询订单信息的逻辑
OrderInfo orderInfo = // ...;
return orderInfo;
}
public ShoppingCart getShoppingCart() {
// 执行查询购物车信息的逻辑
ShoppingCart shoppingCart = // ...;
return shoppingCart;
}
public BankCardPaymentInfo getBankCardPaymentInfo() {
// 执行查询银行卡支付信息的逻辑
BankCardPaymentInfo bankCardPaymentInfo = // ...;
return bankCardPaymentInfo;
}
public void processECommerceRequest() {
UserAccount userAccount = getUserAccount();
OrderInfo orderInfo = getOrderInfo();
ShoppingCart shoppingCart = getShoppingCart();
BankCardPaymentInfo bankCardPaymentInfo = getBankCardPaymentInfo();
// 在这里合并处理各个查询结果
// ...
}
}
以上是接口串行执行的逻辑,当前服务器环境一般都是多核心、多线程,服务器可以同时处理多个任务,如果此时还使用单线程去执行,有些“暴殄天物”,并且接口响应速度会比较慢,那么优化的方式就是开启多个线程去分别执行不同的逻辑,那么我们可以使用CompletableFuture
来优化代码,提高接口响应速度。
import java.util.concurrent.CompletableFuture;
public class ECommerceService {
public CompletableFuture<UserAccount> getUserAccountAsync() {
return CompletableFuture.supplyAsync(() -> {
// 执行查询用户账号信息的逻辑
UserAccount userAccount = // ...;
return userAccount;
});
}
public CompletableFuture<OrderInfo> getOrderInfoAsync() {
return CompletableFuture.supplyAsync(() -> {
// 执行查询订单信息的逻辑
OrderInfo orderInfo = // ...;
return orderInfo;
});
}
public CompletableFuture<ShoppingCart> getShoppingCartAsync() {
return CompletableFuture.supplyAsync(() -> {
// 执行查询购物车信息的逻辑
ShoppingCart shoppingCart = // ...;
return shoppingCart;
});
}
public CompletableFuture<BankCardPaymentInfo> getBankCardPaymentInfoAsync() {
return CompletableFuture.supplyAsync(() -> {
// 执行查询银行卡支付信息的逻辑
BankCardPaymentInfo bankCardPaymentInfo = // ...;
return bankCardPaymentInfo;
});
}
public CompletableFuture<Void> processECommerceRequest() {
CompletableFuture<UserAccount> userAccountFuture = getUserAccountAsync();
CompletableFuture<OrderInfo> orderInfoFuture = getOrderInfoAsync();
CompletableFuture<ShoppingCart> shoppingCartFuture = getShoppingCartAsync();
CompletableFuture<BankCardPaymentInfo> bankCardPaymentInfoFuture = getBankCardPaymentInfoAsync();
return CompletableFuture.allOf(userAccountFuture, orderInfoFuture, shoppingCartFuture, bankCardPaymentInfoFuture)
.thenAcceptAsync((Void) -> {
UserAccount userAccount = userAccountFuture.join();
OrderInfo orderInfo = orderInfoFuture.join();
ShoppingCart shoppingCart = shoppingCartFuture.join();
BankCardPaymentInfo bankCardPaymentInfo = bankCardPaymentInfoFuture.join();
// 在这里合并处理各个异步任务的结果
// ...
});
}
}
以上是账号、订单、购物车、银行卡支付逻辑块各开启一个线程异步去执行,最后等待各个线程执行完毕汇总结果,提高接口影响速度。
单线程和多线程相比,举个不恰当的例子:当你为了报仇,踌躇满志上山叩拜师门,经过十年寒窗苦练、不舍昼夜的练习,终于学成归来下山复仇,结果仇家拿出AK 47一阵突突,云淡风轻的跟你说:“大人,时代变了”的无力感。
CompletableFuture在线程池中执行时,可能会出现代码异常,但是并没有将异常抛出的情况,原因有二:
CompletableFuture
的异步任务中,如果出现异常而没有显式地处理或抛出,那么这个异常就会被吞噬,不会传播到CompletableFuture
的最终结果上。CompletableFuture
的处理过程中,没有正确处理这些异常。例如,在使用thenApply
、exceptionally
等方法对CompletableFuture
的结果进行处理时,没有考虑到可能存在的异常情况,导致异常被掩盖。为了解决这个问题,你可以在异步任务的代码中,适当地处理异常并进行抛出,或者使用exceptionally
方法来处理异常情况,确保异常能够正确地传播并得到处理。此外,在对CompletableFuture
的结果进行处理时,需要注意处理可能发生的异常情况,以确保异常能够被及时捕获和处理。
CompletableFuture
是 Java 8 开始引入的一个用于支持异步编程的工具类,它提供了丰富的 API 来简化异步编程,并提供了对多个异步操作的组合、串行和并行执行的支持。下面是 CompletableFuture 的一些优缺点分析:
优点:
CompletableFuture
提供了简洁的 API,使得异步编程变得更加直观和易于理解。它允许开发者在不同的阶段对异步任务的结果进行处理、转换,甚至是以函数式编程的方式进行流式处理。CompletableFuture
支持多个异步任务的组合、串行和并行执行,可以通过 thenCompose
、thenCombine
等方法灵活地组织复杂的异步任务流程。CompletableFuture
提供了异常处理机制,可以通过 exceptionally
方法对异步任务执行过程中的异常进行处理,从而保证异常能够被正确捕获和处理。CompletableFuture
支持设置异步任务的超时时间,可以通过 orTimeout 方法指定超时时间,防止任务长时间执行导致阻塞。CompletableFuture
运用了函数式编程的思想,使得异步任务的处理更加灵活,并且可以与 Stream 接口等其他函数式编程工具结合使用。缺点:
CompletableFuture
可能会显得过于复杂,特别是在一些简单的线性任务处理中,可能会显得比较繁琐。CompletableFuture
支持异步任务的组合和串行/并行执行,当出现逻辑错误或异常时,可能需要仔细追踪 CompletableFuture
链中的每个环节,以确定问题的所在,这可能会增加调试的难度。综上所述,CompletableFuture
作为 Java 异步编程的利器,提供了丰富的功能和灵活的操作方式,但在使用时需要根据实际情况权衡其优缺点,避免过度复杂化简单的任务处理,并合理处理异常情况以及确保代码的可读性和可维护性。
关于CompletableFuture
的相关实现原理,请您留个关注,明日更新。
感谢您看到最后,希望能解决您的困扰和疑惑,这是我更新最大的动力。
关于我
你好,我是Debug.c。微信公众号:种颗代码技术树 的维护者,一个跨专业自学Java,对技术保持热爱的bug猿,同样也是在某二线城市打拼四年余的Java Coder。
在掘金、CSDN、公众号我将分享我最近学习的内容、踩过的坑以及自己对技术的理解。
如果您对我感兴趣,请联系我。
若有收获,就点个赞吧