惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
L
LangChain Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
罗磊的独立博客
J
Java Code Geeks
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 叶小钗
小众软件
小众软件
博客园 - Franky
D
Docker
Google DeepMind News
Google DeepMind News
Microsoft Azure Blog
Microsoft Azure Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
宝玉的分享
宝玉的分享
C
Check Point Blog
B
Blog
V
V2EX
博客园 - 三生石上(FineUI控件)
MyScale Blog
MyScale Blog
The Cloudflare Blog
博客园 - 聂微东
博客园_首页
Engineering at Meta
Engineering at Meta

博客园 - 五岳

JDK中使用的设计模式 Java的List.sort()排序方法源码理解 Cloud Agent 开发笔记(4):Skill 与 MCP 集成、项目后记 Cloud Agent 开发笔记(3):Web 交互与数据持久化 Cloud Agent 开发笔记(2):Agent 引擎与 Tool 体系 Cloud Agent 开发笔记(1):V1从跑通到放弃 单点登录系统思维导图与资料收集 阿里云DTS按业务场景批量迁移RDS MySQL表实战(下):迁移管理平台设计与实现 阿里云DTS按业务场景批量迁移RDS MySQL表实战(上):技术选型和API对接 分库分表数据源ShardingSphereDataSource的Connection元数据误用问题分析 Web层接口通用鉴权注解实践(基于JDK8) Feign框架中一处编码不合理导致的异常 解决Dify的Ollama插件添加模型时保存成功但模型为空的问题 深入研究使用DozerMapper复制List<Ojbect>前后元素类型不一致的问题 mybatis-config的mapUnderscoreToCamelCase配置生效方式和基本原理 深入理解Mybatis分库分表执行原理 写代码被大语言模型坑之使用LocalDateTime比较两个时间差了几天 系统设计:消灭慢接口 使用LinkedList实现队列和栈 Collectors.toMap的暗坑与避免方式 如丝般顺滑:DDD再实践之类目树管理 阿里云数仓Dataworks数据导出到文件step by step DDD实践反思 LeetCode组合总和I~IV和背包问题小结 Akka学习笔记
封装CompletionService的并发任务分发器(优化版)
五岳 · 2025-06-09 · via 博客园 - 五岳

这个框架代码用了很长时间,使用场景也挺多,初衷是简化CompletionService的编程接口,尽量减少业务代码处的感知。
今天找deepseek做了一版优化,优化点:

  • 整体的超时控制
  • 超时、异常处理和封装
  • 取消未完成的任务

核心代码

public class TaskDispatcher<T> {

    private final CompletionService<T> completionService;

    /**
     * 待处理任务
     */
    private final Set<Future<T>> pending = Sets.newHashSet();

    /**
     * 超时时间, 单位: s
     */
    private long timeout = 10000;

    public TaskDispatcher(Executor executor, long timeout) {
        completionService = new ExecutorCompletionService<>(executor);
        if (timeout > 0) {
            this.timeout = timeout;
        }
    }

    public void submit(Callable<T> task) {
        Future<T> future = completionService.submit(task);
        pending.add(future);
    }

    /**
     * 仅获取执行的任务结果
     *
     * @param ignoreException 忽略执行时发生的异常
     * @return
     */
    public List<T> taskCompletedResult(boolean ignoreException) {
        List<TaskResult<T>> taskResultList = taskCompleted();
        List<T> res = Lists.newArrayList();
        if (CollectionUtils.isEmpty(taskResultList)) {
            return res;
        }
        boolean hasError = false;
        for (TaskResult<T> taskResult : taskResultList) {
            if (!taskResult.isTimeout() && taskResult.getError() == null) {
                res.add(taskResult.getValue());
            } else if (taskResult.isTimeout() && !ignoreException) {
                LoggerUtils.error("执行任务时超时");
                hasError = true;
            } else if (taskResult.getError() != null && !ignoreException) {
                LoggerUtils.error("执行任务时发生异常", taskResult.getError());
                hasError = true;
            }
        }
        if (hasError) {
            throw new ZHException("任务并发处理时发生异常");
        }
        return res;
    }

    /**
     * 获取执行的任务
     *
     * @return
     */
    public List<TaskResult<T>> taskCompleted() {
        long deadline = System.currentTimeMillis() + timeout;
        List<TaskResult<T>> results = Lists.newArrayList();
        int totalTasks = pending.size();

        try {
            for (int i = 0; i < totalTasks; i++) {
                long remaining = Math.max(0, deadline - System.currentTimeMillis());
                Future<T> future = completionService.poll(remaining, TimeUnit.MILLISECONDS);
                TaskResult<T> result = new TaskResult<>();
                if (future == null) {
                    result.setTimeout(true);
                } else {
                    pending.remove(future);
                    try {
                        result.setValue(future.get());
                    } catch (ExecutionException e) {
                        result.setError(e.getCause());
                    }
                }
                results.add(result);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("任务结果收集中断", e);
        } finally {
            pending.forEach(f -> f.cancel(true));
            pending.clear();
        }
        return results;
    }

    @Data
    static class TaskResult<T> {
        private T value;
        private Throwable error;
        private boolean isTimeout;
    }
}

需要自己声明线程池bean,使用方式如下

        TaskDispatcher<Integer> taskDispatcher = new TaskDispatcher<Integer>(threadExecutor, TIME_OUT);
        for (long index: indexList) {
            taskDispatcher.submit(() -> xxxService.count(index));
        }

为了便于在计数求和场景使用,进一步实现了一个子类

public class IntSumTaskDispatcher extends TaskDispatcher<Integer> {
    public IntSumTaskDispatcher(Executor executor, long timeout, boolean throwException) {
        super(executor, timeout);
    }

    /**
     * 对所有结果求和
     *
     * @return
     */
    public int takeCompletedSum() {
        List<Integer> countResList = taskCompletedResult(true);
        int count = 0;
        for (Integer countSingle : countResList) {
            if (countSingle == null) {
                continue;
            }
            count += countSingle;
        }
        return count;
    }
}