源于实际项目中出现任务执行超时或者出现部分任务异常导致整个业务功能失败(兼容java8版本)
先看代码
package tool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.Supplier;
public class CompletableFutureAllOfDemo {
// 全局定时线程池(用于单个任务超时控制,复用避免频繁创建)
private static final ScheduledExecutorService TIMEOUT_SCHEDULER = Executors.newScheduledThreadPool(3);
// 业务线程池(执行异步任务,建议替换为项目自定义线程池)
private static final ExecutorService BUSINESS_EXECUTOR = Executors.newFixedThreadPool(5);
/**
* 封装单个异步任务:含10秒超时 + 全局异常处理
* @param task 业务任务(Supplier类型,无入参有返回值)
* @param taskName 任务名称(用于异常/超时提示)
* @param timeoutDefault 超时默认返回值
* @param exceptionDefault 异常默认返回值
* @return 封装后的CompletableFuture
*/
private static <T> CompletableFuture<T> wrapTask(
Supplier<T> task,
String taskName,
T timeoutDefault,
T exceptionDefault
) {
// 1. 提交业务异步任务
CompletableFuture<T> future = CompletableFuture.supplyAsync(task, BUSINESS_EXECUTOR);
// 2. JDK8实现10秒超时:超时后强制设置默认值
TIMEOUT_SCHEDULER.schedule(() -> {
boolean isTimeout = future.complete(timeoutDefault);
if (isTimeout) {
System.err.println("任务[" + taskName + "]超时(10秒),返回默认值");
}
}, 10, TimeUnit.SECONDS);
// 3. 全局异常处理:捕获任务执行/回调链所有异常
return future.handle((result, ex) -> {
if (ex != null) {
System.err.println("任务[" + taskName + "]执行异常:" + ex.getMessage());
return exceptionDefault;
}
return result; // 正常结果/超时默认值
});
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// ========== 步骤1:定义多个业务任务 ==========
// 任务1:正常执行(模拟耗时5秒)
Supplier<String> task1 = () -> {
try { Thread.sleep(5000); } catch (InterruptedException e) {}
return "任务1正常结果";
};
// 任务2:模拟执行异常
Supplier<String> task2 = () -> {
throw new RuntimeException("数据库查询失败");
};
// 任务3:模拟超时(耗时15秒,超过10秒超时阈值)
Supplier<String> task3 = () -> {
try { Thread.sleep(15000); } catch (InterruptedException e) {}
return "任务3正常结果";
};
// ========== 步骤2:封装每个任务(超时+异常处理) ==========
CompletableFuture<String> future1 = wrapTask(task1, "任务1", "任务1超时默认值", "任务1异常默认值");
CompletableFuture<String> future2 = wrapTask(task2, "任务2", "任务2超时默认值", "任务2异常默认值");
CompletableFuture<String> future3 = wrapTask(task3, "任务3", "任务3超时默认值", "任务3异常默认值");
// ========== 步骤3:使用allOf等待所有任务完成 ==========
CompletableFuture<Void> allFuture = CompletableFuture.allOf(future1, future2, future3);
// 阻塞等待所有任务(无论成功/失败/超时)执行完毕
allFuture.get();
// ========== 步骤4:收集所有任务的最终结果 ==========
List<String> results = new ArrayList<>();
results.add(future1.get()); // 任务1:正常结果
results.add(future2.get()); // 任务2:异常默认值
results.add(future3.get()); // 任务3:超时默认值
// 打印最终结果
System.out.println("所有任务结果:");
for (String result : results) {
System.out.println("- " + result);
}
// ========== 步骤5:关闭线程池(项目关闭时执行) ==========
TIMEOUT_SCHEDULER.shutdown();
BUSINESS_EXECUTOR.shutdown();
}
}
输出结果:

优化点说明:
1.由于之前异步任务写得比较简陋,这里做了一个方法提取,增加了10秒超时和全局异常捕获
2.不再在无返回结果的任务中用Map收集结果,而是在结束之后统一收集结果,每一个异步任务结果返回
3.之前用runAsyn改成supplyAsyn

4.不用Executors的方式创建线程池,而用ThreadPoolTaskExecutor方式创建


5.两个线程池隔离分开(全局调度线程池和业务执行线程池),而非共用一个线程池,且用@Autowaired注入类中,通过方法参数传递进去,注意ThreadPoolTaskExecutor 是 Spring 框架(spring-context 模块)提供的线程池实现

隔离的好处:1.资源抢占风险隔离2.故障域隔离3.监控和调优更精准

在 Spring/Spring Boot 项目中,推荐使用 ThreadPoolTaskExecutor(而非原生 ThreadPoolExecutor),因为它更贴合 Spring 生态,支持 Spring 的生命周期管理、线程池监控、优雅关闭等特性。
异步任务
异步任务,默认使用ForkJoinPool.commonPool(),也可指定自定义线程池。
- 无返回值:
CompletableFuture.runAsync(Runnable) - 有返回值:
CompletableFuture.supplyAsync(Supplier)

1168

被折叠的 条评论
为什么被折叠?



