关于ExecutorFuture 多线程 同步与异步编程的基本概念,使用异步编排的原因
-
同步编程:指程序执行某个任务时,当前线程会被阻塞,直到任务完成。在这种模式下,后续代码需要等待前一个任务的完成。
-
异步编程:在执行任务时,当前线程不会被阻塞,任务会交给其他线程来执行。任务完成后,通常通过回调或通知的方式来处理结果。
-
提高效率:在复杂的操作如商品详情页查询中,涉及多个远程调用(RPC),异步可以减少等待时间。例如,使用异步可以将响应时间从3.5秒减少到1.5秒。
-
任务依赖管理:在异步化操作时,需要确保任务的依赖关系,例如在获取用户信息时可能需要先获取分类信息。
一. 定义一个多线程的返回结果对象接口类
/** 多线程并发返回结果对象接口类实现**/
public interface FutureResponse {
}
二. 定义一个多线程构建具体的并发任务接口类
/** 多线程构建具体的并发任务接口类**/
public interface FutureRequest {
}
三. 定义一个多线程构建具体的线程接口类
/** 多线程构建具体的线程接口类**/
public interface FutureCallableOrder<T> extends Callable<T>, Ordered {
}
四. 抽象一个多线程具体的实现抽象类
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
/**
* @author 作者 : suven
* @date 创建时间: 2023-12-11
* @version 版本: v1.0.0
* <pre>
*
* @description (说明):
* </pre>
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 修改内容:
* </pre>
**/
public abstract class AbstractFutureCallableRoute<R extends FutureRequest,V extends FutureResponse > implements FutureCallableOrder<V>{
private final int order;
private final R request;
private final String traceId;
public AbstractFutureCallableRoute(int order, R requestParameter) {
this.order = order;
this.request = requestParameter;
this.traceId = TraceContext.traceId();
}
/**
* Get the order value of this object.
* <p>Higher values are interpreted as lower priority. As a consequence,
* the object with the lowest value has the highest priority (somewhat
* analogous to Servlet {@code load-on-startup} values).
* <p>Same order values will result in arbitrary sort positions for the
* affected objects.
*
* @return the order value
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
@Override
public int getOrder() {
return order;
}
public R getRequest(){
return request;
}
/**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,
* 则该方法自动在一个线程上执行
*/
public V call() throws Exception {
callTraceId();
return calling();
}
public void callTraceId(){
TraceContext.putCorrelation("traceId",traceId);
}
public abstract V calling() throws Exception;
}
五.静态方法callFuture,用于执行多个并发任务。它接收一个FutureCallableRoute对象的列表作为参数,将每个任务提交给线程池进行执行,并将执行结果保存在Future对象的列表中
/** 该类包含了一个静态方法callFuture,用于执行多个并发任务。它接收一个FutureCallableRoute对象的列表作为参数,将每个任务提交给线程池进行执行,并将执行结果保存在Future对象的列表中。然后,通过遍历Future列表,并使用get()方法获取每个任务的执行结果,并将结果存储在结果列表中。最后,关闭线程池。
以上就是这段代码的简要介绍。它提供了一种利用线程池并发执行任务并获取结果的方式。通过使用ExecutorService和Future接口
**/
import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.*;
import java.util.stream.Collectors;
/**
* @author 作者 : suven
* date 创建时间: 2023-12-08
* @version 版本: v1.0.0
* <pre>
*
* description (说明):
* </pre>
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 修改内容:
* </pre>
**/
@Slf4j
public class ExecutorFuture {
private static class SingletonFuture {
static ExecutorFuture INSTANCE = new ExecutorFuture();
}
/**
* 线程池初始化方法
*
* corePoolSize 核心线程池大小----10
* maximumPoolSize 最大线程池大小----1000
* keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit
* TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES
* workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(10)====10容量的阻塞队列
* threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂
* rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,
* 即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)),
* 任务会交给RejectedExecutionHandler来处理
*/
private final static ExecutorService executors = new ThreadPoolExecutor(
10, 20, 5,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100000),
new ThreadFactoryBuilder().setNameFormat("pick-logger-worker-%d").build());
private ExecutorFuture(){}
public ExecutorFuture instance(){
return SingletonFuture.INSTANCE;
}
public static enum FutureErrorCode {
SYS_COMPLETABLE_FUTURE_TIMEOUT(1100057, "异步线程调用业务超时异常[ %s ]"),
SYS_COMPLETABLE_FUTURE_EXCEPTION(1100058, "异步线程调用业务超时异常[ %s ]"),
SYS_COMPLETABLE_FUTURE_INTERRUPTED(1100059, "异步线程恢复线程中断状态[ %s ]"),
SYS_COMPLETABLE_BUILD_EXCEPTION(1100060, "异步线程创建异常[ %s ]"),
SYS_COMPLETABLE_FUTURE_LIST_EMPTY(1100061, "callableFutureList cannot be null or empty"),
;
private int code;
private String msg;
FutureErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
public static <R,F extends Callable<R>> List<R> callFuture(List<F> futureResultList) {
List<Future<R>> futureList = new ArrayList<>();
List<R> resultList = new ArrayList<>();
//创建10个任务并执行
futureResultList.forEach(callable -> {
//使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
Future<R> future = executors.submit(callable);
//将任务执行结果存储到List中
futureList.add(future);
});
futureList.forEach(future ->{
try{
while(!future.isDone()){
};//Future返回如果没有完成,则一直循环等待,直到Future返回完成
R result = future.get();
//各个线程(任务)执行的结果
resultList.add(result);
}catch(Exception e){
log.info("callFutureMap futureResultList[{}] , Exception:[{}] ",JSON.toJSONString(futureResultList),e);
}
} );
return resultList;
}
public static <T extends FutureResponse,F extends Callable<T>> Map<Integer, T> callFutureMap(List<F> futureResultList) {
List<Future<T>> futureList = new ArrayList<>();
Map<Integer, T> resultMap = new TreeMap<>();
//创建10个任务并执行
futureResultList.forEach(callable -> {
//使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
Future<T> future = executors.submit(callable);
//将任务执行结果存储到List中
futureList.add(future);
});
futureList.forEach(future ->{
try{
while(!future.isDone());//Future返回如果没有完成,则一直循环等待,直到Future返回完成
T result = future.get();
log.info("callFutureMap futureResultList[{}] ",JSON.toJSONString(result));
//各个线程(任务)执行的结果
resultMap.put(result.getOrder(),result);
}catch (RuntimeException runtimeException){
throw runtimeException;
} catch(Exception e){
log.info("callFutureMap futureResultList[{}] , Exception:[{}] ",JSON.toJSONString(futureResultList),e);
}
} );
return resultMap;
}
public static <T extends FutureResponse,F extends Callable<T>> Map<Integer, T> callFutureMapEx(List<F> futureResultList) {
List<Future<T>> futureList = new ArrayList<>();
Map<Integer, T> resultMap = new TreeMap<>();
//创建10个任务并执行
futureResultList.forEach(callable -> {
//使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
Future<T> future = executors.submit(callable);
//将任务执行结果存储到List中
futureList.add(future);
});
futureList.forEach(future ->{
try {
while (!future.isDone()) ;//Future返回如果没有完成,则一直循环等待,直到Future返回完成
T result = future.get();
log.info("callFutureMap futureResultList[{}] ", JSON.toJSONString(result));
//各个线程(任务)执行的结果
resultMap.put(result.getOrder(), result);
} catch (RuntimeException runtimeException){
throw runtimeException;
}catch(Exception e){
log.info("callFutureMap futureResultList[{}] , Exception:[{}] ",JSON.toJSONString(futureResultList),e);
}
} );
return resultMap;
}
/**
* 提交Callable任务列表到执行器服务,并返回Future对象列表
* 该方法允许批量提交Callable任务,每个任务代表一个异步计算
* 使用泛型参数R和F,其中R是计算结果类型,F是实现了Callable接口的类型
*
* @param futureResultList 包含一系列实现了Callable接口的实例列表
* 列表中的每个元素代表一个可以异步执行的任务
* @return 返回一个包含Future对象的列表,每个Future对象代表一个提交的任务
* 可以通过Future对象来获取任务执行结果或取消任务
*/
public static <R, F extends Callable<R>> List<Future<R>> submitCallables(List<F> futureResultList) {
// 创建一个空的Future列表,用于存储提交任务后返回的Future对象
List<Future<R>> futureList = new ArrayList<>();
// 遍历Callable任务列表,提交每个任务到执行器服务
futureResultList.forEach(callable -> {
// 提交任务并获取Future对象
Future<R> future = executors.submit(callable);
// 将Future对象添加到列表中
futureList.add(future);
});
// 返回包含所有任务的Future对象列表
return futureList;
}
/**
* 异步执行一个 Callable 任务,并根据参数决定是否获取任务结果。
* 该方法使用 CompletableFuture.runAsync 和 FutureTask 来实现异步任务的执行,
* 并支持超时控制和异常处理。
*
* @param executor 用于执行任务的线程池。负责管理任务的异步执行。
* @param callableFuture 需要执行的 Callable 任务,任务执行完成后会返回一个结果。
* @param parameter 任务执行的参数配置,包含是否需要获取结果、超时时间以及业务描述等信息。
* @return 如果参数允许获取结果,则返回任务的执行结果;否则返回 null。
* @throws RuntimeException 如果任务执行超时或发生其他异常,会抛出业务异常,异常信息由参数中的业务描述生成。
*/
public static <V>V completableFutureRun(ExecutorService executor, Callable<V> callableFuture, FutureParameter parameter) {
if (callableFuture == null ){
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_LIST_EMPTY.getMsg());
}
// 将 Callable 包装为 FutureTask,以便通过 CompletableFuture.runAsync 执行任务
FutureTask<V> futureTask = new FutureTask<>(callableFuture);
// 使用 CompletableFuture.runAsync 方法异步执行任务
CompletableFuture.runAsync(futureTask, executor);
// 如果参数为空或不需要获取结果,则直接返回 null
if (parameter == null || !parameter.isFutureResult()) {
return null;
}
// 获取任务结果,支持超时控制
V result = null;
try {
// 根据参数中的超时时间决定如何获取任务结果
if (parameter.getTimeout() > 0) {
result = futureTask.get(parameter.getTimeout(), TimeUnit.SECONDS);
} else {
result = futureTask.get();
}
return result;
} catch (TimeoutException e) {
// 如果任务执行超时,抛出业务异常,异常信息包含业务描述
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_TIMEOUT.getMsg());
} catch (Exception e) {
// 捕获其他异常,抛出业务异常,异常信息包含具体错误消息
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_EXCEPTION.getMsg());
}
}
/**
* 批量异步执行 Callable 任务列表,并根据参数决定是否获取任务结果。
* 该方法使用 CompletableFuture 和 FutureTask 实现异步任务的批量执行,
* 并支持超时控制和异常处理。
*
* @param executor 用于执行任务的线程池。负责管理任务的异步执行。
* @param callableFutureList 需要执行的 Callable 任务列表,每个任务代表一个异步计算。
* 列表不能为空或 null。
* @param parameter 任务执行的参数配置,包含是否需要获取结果、超时时间以及业务描述等信息。
* @return 如果参数允许获取结果,则返回包含所有任务执行结果的列表;
* 如果参数无效或未启用 futureResult,则返回空列表。
* @throws IllegalArgumentException 如果 callableFutureList 为 null 或空。
* @throws RuntimeException 如果任务执行超时或发生其他异常,会抛出业务异常。
* 方法说明
* 参数校验:
* 确保 callableFutureList 不为 null 且不为空。
* 如果 parameter 为 null 或未启用 futureResult,直接返回空列表。
* 任务提交:
* 使用 CompletableFuture.supplyAsync 提交任务到线程池,并将每个任务包装为 CompletableFuture 对象。
* 等待任务完成:
* 使用 CompletableFuture.allOf 等待所有任务完成。
* 如果任务执行过程中发生异常且允许中断,则抛出自定义业务异常。
* 结果收集:
* 遍历所有 CompletableFuture 对象,获取任务结果。
* 支持超时控制,处理超时、中断和其他异常情况。
* 异常处理:
* 超时异常:抛出业务异常,异常信息包含业务描述。
* 中断异常:恢复线程中断状态并抛出业务异常。
* 其他异常:捕获并抛出业务异常,异常信息包含具体错误消息。
*/
public static <V> boolean completableFutureRunList( ExecutorService executor, List<Callable<V>> callableFutureList, FutureParameter parameter) {
// 参数校验:确保 callableFutureList 不为 null 且不为空
if (callableFutureList == null || callableFutureList.isEmpty()) {
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_LIST_EMPTY.getMsg());
}
// 使用 Stream 模式提交任务并存储 CompletableFuture 对象
@NotNull
List<CompletableFuture<Void>> futures = callableFutureList.stream()
.map(callableFuture -> CompletableFuture.runAsync(new FutureTask<>(callableFuture), executor)).collect(Collectors.toList());
// 等待所有任务完成,如果发生异常且允许中断,则抛出自定义业务异常
try {
// 如果参数无效(parameter 为 null 或未启用 futureResult),直接返回空列表
if (parameter != null &¶meter.isFutureResult()) {
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
} catch (CompletionException e) {
if (parameter.isInterrupt()) {
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_EXCEPTION.getMsg(),e);
}
}
return true;
}
/**
* 执行一组异步任务并收集结果。
*
* @param executor 用于执行异步任务的线程池。
* @param callableFutureList 包含 Callable 任务的列表,每个任务将被提交到线程池中执行。
* 不能为 null 或空列表。
* @param parameter 控制任务执行行为的参数对象,包含是否中断、超时时间等信息。
* 如果为 null 或未启用 futureResult,则直接返回 null。
* @param <V> 任务返回值的类型。
* @param <Future> 继承自 Callable 的任务类型。
* @return 如果参数有效且任务成功完成,则返回包含所有任务结果的列表;
* 如果参数无效或任务未启用 futureResult,则返回 null。
* @throws IllegalArgumentException 如果 callableFutureList 为 null 或空。
* @throws CompletionException 如果任务执行过程中发生异常且参数允许中断。
*/
public static <V, Future extends Callable<V>> List<V> completableFutureList(ExecutorService executor, List<Future> callableFutureList, FutureParameter parameter) {
// 参数校验:确保 callableFutureList 不为 null 且不为空
// 参数校验:确保 callableFutureList 不为 null 且不为空
if (callableFutureList == null || callableFutureList.isEmpty()) {
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_LIST_EMPTY.getMsg());
}
// 使用 Stream 模式提交任务并存储 CompletableFuture 对象
List<CompletableFuture<V>> futures = callableFutureList.stream()
.map(callableFuture -> CompletableFuture.supplyAsync(() -> {
try {
return callableFuture.call();
} catch (Exception e) {
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_BUILD_EXCEPTION.getMsg(),e);
}
}, executor))
.collect(Collectors.toList());
// 等待所有任务完成,如果发生异常且允许中断,则抛出自定义业务异常
try {
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
} catch (CompletionException e) {
if (parameter.isInterrupt()) {
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_EXCEPTION.getMsg(),e);
}
}
// 如果参数无效(parameter 为 null 或未启用 futureResult),直接返回 null
if (parameter == null || !parameter.isFutureResult()) {
return null;
}
// 收集任务结果,处理超时、中断和其他异常情况
List<V> resultList = new ArrayList<>();
for (CompletableFuture<V> future : futures) {
try {
V result;
if (parameter.getTimeout() > 0) {
result = future.get(parameter.getTimeout(), TimeUnit.SECONDS);
} else {
result = future.get();
}
resultList.add(result);
} catch (TimeoutException e) {
if (parameter.isInterrupt()) {
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_TIMEOUT.getMsg(), e);
}
} catch (InterruptedException e) {
if (parameter.isInterrupt()) {
Thread.currentThread().interrupt(); // 恢复线程中断状态
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_INTERRUPTED.getMsg(),e);
}
} catch (Exception e) {
if (parameter.isInterrupt()) {
throw new RuntimeException(FutureErrorCode.SYS_COMPLETABLE_FUTURE_EXCEPTION.getMsg(),e);
}
}
}
return resultList;
}
}
六. 线程线程跟踪实现
/**
* 业务传递当前线程线路id,如何为空时,初始化uuid链路id
*/
public static String initTraceId(){
String traceId = TraceContext.traceId();
if (Objects.isNull(traceId)){
traceId = UUID.randomUUID().toString();
}
TraceContext.putCorrelation("traceId",traceId);
return traceId;
}
2.线程控制参数对象类
import lombok.Data;
@Data
public class FutureParameter {
// 超时时间,单位为秒
private long timeout;
// 是否返回结果
private boolean isFutureResult;
// 业务描述
private String bizDesc;
//线程异常是否中断
private boolean isInterrupt = true;
public static FutureParameter build(long timeout, boolean isFutureResult, String bizDesc) {
FutureParameter parameter = new FutureParameter();
parameter.setTimeout(timeout);
parameter.setFutureResult(isFutureResult);
parameter.setBizDesc(bizDesc);
return parameter;
}
public static FutureParameter build(String bizDesc) {
FutureParameter parameter = new FutureParameter();
parameter.setTimeout(3000);
parameter.setFutureResult(false);
parameter.setBizDesc(bizDesc);
parameter.setInterrupt(true);
return parameter;
}
}
- 在创建线程(FutureCallableRoute)继承类的构造器中执行initTraceId()初始化路线唯一字符串
- 在执行运行线程中,输入以下代码,即可
TraceContext.putCorrelation("traceId",traceId);
七.关于ExecutorFuture类的结构和功能:
-
.
ExecutorFuture类是一个单例类,通过私有的构造函数和静态内部类实现了单例模式。这确保了只有一个ExecutorFuture实例存在。 -
ExecutorFuture类包含了一个静态的ExecutorService对象executors,它是一个线程池。线程池在代码中通过ThreadPoolExecutor进行初始化,指定了核心线程数、最大线程数、线程空闲时间等参数。 -
ExecutorFuture类的callFuture方法是用于执行多个并发任务的关键方法。它接收一个FutureCallableRoute对象的列表futureResultList作为参数,表示要执行的并发任务列表。 -
在
callFuture方法中,首先创建了两个空列表:futureList用于存储Future对象,resultList用于存储任务的执行结果。 -
然后,通过遍历
futureResultList列表,对于每个FutureCallableRoute对象,使用线程池的submit方法提交任务并返回一个Future对象。将这些Future对象添加到futureList中。 -
接下来,使用
futureList列表进行遍历,对于每个Future对象,通过isDone方法判断任务是否完成,如果任务未完成,则通过循环等待,直到任务完成。 -
当任务完成后,通过
get方法获取任务的执行结果,并将结果存储在resultList中。 -
最后,关闭线程池,通过调用
executors.shutdown()方法来实现。
这段代码的目的是实现多线程并发执行任务,并且能够按照一定的顺序获取任务的执行结果。它使用了Java的线程池和Future接口来管理和控制任务的执行,并通过Future对象获取任务的执行结果。
在使用这段代码时,您需要提供具体的实现类来继承FutureCallableRoute,并实现其中的call方法,用于定义具体的任务逻辑。然后,将这些实现类对象添加到futureResultList中,并调用callFuture方法来执行并发任务。
请注意,代码中的线程池参数和队列大小等可以根据您的需求进行调整。同时,您也可以根据具体的业务场景对代码进行修改和扩展。
八. CompletableFuture 异步编排。先阐述了同步和异步概念,指出使用异步编排的原因。接着详细讲解了 CompletableFuture 的学习,包括多种方法及对比。然后通过实战案例展示其应用,最后说明了异步编排的使用场景,如并行调用微服务、批量处理任务等,强调其在优化性能和处理复杂流程中的作用。
1. Future和CompletableFuture
-
Future的局限性:
-
结果获取方法
future.get()是阻塞的。
-
任务组合功能不足,难以处理复杂异步任务链。
-
异常处理复杂。
-
-
CompletableFuture的优势:
-
支持非阻塞操作,并提供
thenApply、thenAccept等方法来执行后续操作。
-
便捷的任务组合能力,如
thenCombine、allOf。 -
异常处理简洁,提供
exceptionally等方法。
-
可构建复杂的异步流程,提高代码可读性与维护性。
-
2. CompletableFuture的使用 在 JDK 8 中引入,提供了更强大和灵活的异步编程支持。它不仅可以用来表示异步计算的结果,还提供了许多方便的方法来处理异步任务的执行和结果处理。以下是 CompletableFuture 的一些主要用途:
-
核心方法:
-
异步计算:
runAsync:启动不需要返回值的异步任务,用于记录日志等。 -
非阻塞操作:
supplyAsync:启动需要返回结果的异步任务,如计算或数据获取。 -
组合多个异步任务:
CompletableFuture提供了方法来组合多个异步任务,例如whenComplete与exceptionally:处理任务完成及异常情况,相当于Java 中的then和catch。 -
阻塞操作:
thenApply和thenAccept:前者处理结果并返回新值,后者处理结果但不返回新值。 -
处理异常:
exceptionally:类似于 Vue 中发起异步请求之后的catch方法,只有当任务发生异常时才会执行,可以用于处理异步任务中的异常,并返回一个替代结果。。 -
Async后缀:
thenApplyAsync
-
3. 实战案例
具体的使用例子:
public class FutureExceptionally {
public static void main(String[] args) throws Exception {
System.out.println("在主线程打印日志,启动异步运行异常线程--开始");
runAsyncException();
System.out.println("在主线程打印日志,启动异步运行异常线程--结果");
SleepUtils.sleep(3);
}
//发起一个异步请求
public static void runAsyncException() {
CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
System.out.println("在异步线程中打印日志,异步运行中,抛出运行异常线程");
//int result =100/0;
throw new RuntimeException("异步线程中,主动抛出运行异常");
}
}).whenComplete(new BiConsumer<Void, Throwable>() {
@Override
public void accept(Void acceptVal, Throwable throwable) {
System.out.println("执行异步之后通过whenComplete请求参数"+acceptVal);
System.out.println("执行异步之后通过whenComplete抛出异常值"+throwable);
}
}).exceptionally(new Function<Throwable, Void>() {
@Override
public Void apply(Throwable throwable) {
System.out.println("执行异步之后exceptionally异常值"+throwable);
System.out.println("执行异步之后,处理期望要处理的业务实现");
return null;
}
});
}
}
4. 异步编排的应用场景
- 并行调用微服务:如电商平台需要同时调用多个服务。
- 异步批量任务处理:例如批量用户数据的导入和校验。
- 用户请求的异步处理:从多个数据源获取并合并返回。
- 复杂工作流执行:步骤多且需异步执行的业务流程。
希望这些信息能够帮助您更好地理解这段代码。如果您有任何进一步的问题,请随时提问。