CompletableFuture并行任务超时处理模板

java 复制代码
import java.util.List;
import java.util.concurrent.*;
import java.util.function.Supplier;

/**
 * CompletableFuture并行任务超时处理模板
 * 功能:
 * 1. 单个任务独立超时控制 + 降级处理
 * 2. 整体任务汇总超时控制
 * 3. 自定义线程池避免资源耗尽
 * 4. 异常统一处理
 */
public class CompletableFutureTemplate {

    // 自定义线程池(核心参数可根据业务调整)
    private static final ThreadPoolExecutor CUSTOM_EXECUTOR = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(), // 核心线程数(CPU核心数)
            Runtime.getRuntime().availableProcessors() * 2, // 最大线程数
            60, TimeUnit.SECONDS, // 空闲线程存活时间
            new LinkedBlockingQueue<>(100), // 任务队列(避免无限扩容)
            new ThreadFactory() { // 线程命名(便于问题排查)
                private int count = 0;
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setName("parallel-task-" + count++);
                    thread.setDaemon(false); // 非守护线程,避免主线程退出后被强制终止
                    return thread;
                }
            },
            new ThreadPoolExecutor.CallerRunsPolicy() // 队列满时,让提交任务的线程执行(限流+避免任务丢失)
    );

    /**
     * 并行执行多个任务,支持单个任务超时和整体超时
     * @return 汇总后的业务结果
     */
    public BusinessResult executeParallelTasks() {
        try {
            // 1. 定义并行任务(可根据业务增减)
            CompletableFuture<Task1Result> task1 = wrapWithTimeout(
                    this::doTask1, // 任务1:实际业务逻辑
                    300, TimeUnit.MILLISECONDS, // 超时时间
                    this::getTask1Fallback // 超时/异常时的降级数据
            );

            CompletableFuture<Task2Result> task2 = wrapWithTimeout(
                    this::doTask2, // 任务2:易超时的业务(如房源推荐)
                    500, TimeUnit.MILLISECONDS, // 超时时间可适当延长
                    this::getTask2Fallback
            );

            CompletableFuture<Task3Result> task3 = wrapWithTimeout(
                    this::doTask3, // 任务3:快速任务
                    200, TimeUnit.MILLISECONDS,
                    this::getTask3Fallback
            );

            // 2. 等待所有任务完成(整体超时控制)
            CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2, task3);
            // 整体超时时间:取单个任务超时的最大值 + 冗余时间(避免单个任务接近超时导致整体超时)
            allTasks.get(800, TimeUnit.MILLISECONDS);

            // 3. 汇总结果(join()不会抛出受检异常,因已通过wrapWithTimeout处理)
            return new BusinessResult(
                    task1.join(),
                    task2.join(),
                    task3.join()
            );

        } catch (TimeoutException e) {
            // 整体超时:返回更基础的降级结果(如只保留核心数据)
            log.warn("整体任务超时,返回基础降级结果");
            return getOverallFallback();
        } catch (Exception e) {
            // 其他异常(如线程池满):返回应急降级结果
            log.error("并行任务执行异常", e);
            return getEmergencyFallback();
        }
    }

    /**
     * 包装任务:添加超时控制和降级处理
     * @param task 实际任务
     * @param timeout 超时时间
     * @param unit 时间单位
     * @param fallback 降级策略
     * @param <T> 任务返回类型
     * @return 包装后的CompletableFuture
     */
    private <T> CompletableFuture<T> wrapWithTimeout(
            Supplier<T> task,
            long timeout,
            TimeUnit unit,
            Supplier<T> fallback) {

        return CompletableFuture.supplyAsync(() -> {
                    try {
                        // 执行实际任务(若任务支持中断,可在此处处理中断逻辑)
                        return task.get();
                    } catch (Exception e) {
                        // 任务执行中抛出异常:直接降级
                        log.error("任务执行异常,触发降级", e);
                        return fallback.get();
                    }
                }, CUSTOM_EXECUTOR)
                // 超时后直接返回降级数据(无需抛异常)
                .completeOnTimeout(fallback.get(), timeout, unit)
                // 额外处理可能的异常(如线程池拒绝)
                .exceptionally(ex -> {
                    log.error("任务超时或被中断,触发降级", ex);
                    return fallback.get();
                });
    }

    // ------------------------------
    // 以下为业务相关方法(需根据实际场景实现)
    // ------------------------------

    /** 任务1:示例业务(如获取用户信息) */
    private Task1Result doTask1() {
        // 实际业务逻辑:如调用用户服务API
        return new Task1Result("user123", "张三");
    }

    /** 任务1降级数据 */
    private Task1Result getTask1Fallback() {
        // 降级策略:返回默认用户信息或缓存数据
        return new Task1Result("default", "匿名用户");
    }

    /** 任务2:示例易超时业务(如房源推荐) */
    private Task2Result doTask2() {
        // 实际业务逻辑:如调用推荐服务API(可能耗时较长)
        return new Task2Result(List.of("house_101", "house_102"));
    }

    /** 任务2降级数据 */
    private Task2Result getTask2Fallback() {
        // 降级策略:返回热门房源缓存
        return new Task2Result(List.of("house_hot_01", "house_hot_02"));
    }

    /** 任务3:示例快速业务(如获取价格趋势) */
    private Task3Result doTask3() {
        // 实际业务逻辑:如查询缓存中的价格趋势
        return new Task3Result(10000.0, 10500.0); // 昨日均价,今日均价
    }

    /** 任务3降级数据 */
    private Task3Result getTask3Fallback() {
        // 降级策略:返回默认趋势或空数据
        return new Task3Result(0.0, 0.0);
    }

    /** 整体超时降级结果 */
    private BusinessResult getOverallFallback() {
        // 策略:只保留核心任务的降级数据
        return new BusinessResult(
                getTask1Fallback(), // 核心任务:用户信息不能丢
                getTask2Fallback(),
                new Task3Result(null, null) // 非核心任务可返回空
        );
    }

    /** 应急降级结果(极端异常时) */
    private BusinessResult getEmergencyFallback() {
        // 策略:只返回最基础的可用数据
        return new BusinessResult(
                new Task1Result("emergency", "系统维护中"),
                new Task2Result(List.of()),
                new Task3Result(null, null)
        );
    }

    // ------------------------------
    // 以下为业务模型类(示例)
    // ------------------------------
    static class BusinessResult {
        private Task1Result userInfo;
        private Task2Result houseRecommend;
        private Task3Result priceTrend;

        public BusinessResult(Task1Result userInfo, Task2Result houseRecommend, Task3Result priceTrend) {
            this.userInfo = userInfo;
            this.houseRecommend = houseRecommend;
            this.priceTrend = priceTrend;
        }
        // getters/setters
    }

    static class Task1Result {
        private String userId;
        private String userName;
        // 构造器、getters/setters
        public Task1Result(String userId, String userName) {
            this.userId = userId;
            this.userName = userName;
        }
    }

    static class Task2Result {
        private List<String> houseIds;
        // 构造器、getters/setters
        public Task2Result(List<String> houseIds) {
            this.houseIds = houseIds;
        }
    }

    static class Task3Result {
        private Double yesterdayPrice;
        private Double todayPrice;
        // 构造器、getters/setters
        public Task3Result(Double yesterdayPrice, Double todayPrice) {
            this.yesterdayPrice = yesterdayPrice;
            this.todayPrice = todayPrice;
        }
    }

    // 日志工具(实际项目中替换为SLF4J等)
    private static void log(String msg) {
        System.out.println("[INFO] " + msg);
    }

    private static void log(String msg, Throwable e) {
        System.err.println("[ERROR] " + msg + ":" + e.getMessage());
    }
}

模板核心特性说明

  1. 分层超时控制
    • 单个任务超时:通过 completeOnTimeout 为每个任务设置独立超时时间(如任务2设500ms,适合房源推荐等耗时不稳定的场景)
    • 整体任务超时:通过 allTasks.get(800ms) 控制总耗时,避免单个任务接近超时导致整体响应变慢
  2. 多级降级策略
    • 单任务降级:每个任务超时/异常时返回预设降级数据(如房源推荐超时返回热门房源缓存)
    • 整体降级:整体超时时返回核心数据(如只保留用户信息,舍弃非核心的价格趋势)
    • 应急降级:极端异常(如线程池满)时返回最基础可用数据,保证接口不报错
  3. 线程池安全管理
    • 自定义线程池:避免使用默认 ForkJoinPool 导致的资源耗尽问题
    • 线程命名:便于日志排查具体任务的问题
    • 拒绝策略:采用 CallerRunsPolicy,让提交任务的线程执行,既限流又避免任务丢失
  4. 异常全面处理
    • 任务执行异常:通过 try-catch 捕获并降级
    • 超时异常:通过 completeOnTimeoutexceptionally 双重保障
    • 整体异常:统一捕获并返回应急结果

使用时的调整建议

  1. 超时时间设置
    • 单个任务:根据历史耗时95分位值设置(如95%的请求在300ms内完成,则设300ms)
    • 整体超时:单个任务最大超时 + 20%冗余(避免网络波动导致整体超时)
  2. 降级数据设计
    • 核心任务(如用户信息):降级数据需可用(如缓存的历史信息)
    • 非核心任务(如推荐列表):可返回空或默认数据,但需保证前端兼容
  3. 线程池参数
    • 核心线程数:CPU核心数(IO密集型任务可适当增加)
    • 队列大小:根据并发量设置(如支持100并发,则队列设100)
  4. 中断支持
    • 若任务涉及IO操作(如HTTP请求、数据库查询),建议使用支持中断的API(如 CloseableHttpClient),超时后可主动释放资源

通过此模板,可有效避免单个任务超时阻塞整体接口,同时保证系统在异常情况下的可用性和稳定性。

相关推荐
java1234_小锋4 小时前
TensorFlow2 Python深度学习 - TensorFlow2框架入门 - 计算图和 tf.function 简介
python·深度学习·tensorflow·tensorflow2
程序员晚枫4 小时前
Python 3.14新特性:Zstandard压缩库正式加入标准库,性能提升30%
python
逆境清醒4 小时前
VS Code配置Python开发环境系列(1)___VScode的安装 ,VScode常用快捷键
vscode·python·visual studio code
珹洺4 小时前
Java-Spring入门指南(二十一)Thymeleaf 视图解析器
java·开发语言·spring
源码集结号4 小时前
一套智慧工地云平台源码,支持监管端、项目管理端,Java+Spring Cloud +UniApp +MySql技术开发
java·mysql·spring cloud·uni-app·源码·智慧工地·成品系统
EnCi Zheng4 小时前
Spring Security 最简配置完全指南-从入门到精通前后端分离安全配置
java·安全·spring
程序员小假4 小时前
为什么这些 SQL 语句逻辑相同,性能却差异巨大?
java·后端
万粉变现经纪人5 小时前
如何解决 pip install -r requirements.txt 无效可编辑项 ‘e .‘(-e 拼写错误)问题
开发语言·python·r语言·beautifulsoup·pandas·pip·scipy
say_fall5 小时前
精通C语言(2.结构体)(内含彩虹)
c语言·开发语言·windows