You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ExecutorService获取所有任务结果(含超时与失败处理)

使用ExecutorService实现带超时的多任务执行及结果处理

嘿,这个需求我熟!用ExecutorService结合Future完全能完美解决,我给你拆解清楚步骤,再附上可直接运行的代码示例,你一看就懂:

核心思路

  • 用Executors.newFixedThreadPool(5)创建固定大小的线程池,刚好匹配你的5个任务需求
  • 把每个任务封装成Callable实现类,这样既能返回执行结果,也能捕获执行过程中的异常
  • 用ExecutorService.invokeAll()方法批量提交任务并设置统一超时时间,这个方法比逐个调用future.get()更高效,还能统一处理超时场景
  • 遍历返回的Future集合,分别处理正常完成、超时、执行异常三种情况,给每个任务标记对应的状态(比如你要的Failed,还有Success、Timeout)

完整代码示例

首先定义任务状态枚举和任务类:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

// 任务状态枚举,包含你需要的Failed状态
enum TaskStatus {
    SUCCESS, FAILED, TIMEOUT
}

// 自定义任务类,实现Callable接口,维护状态和结果
class Task implements Callable<String> {
    private final String taskName;
    private TaskStatus status;
    private String result;

    public Task(String taskName) {
        this.taskName = taskName;
    }

    @Override
    public String call() throws Exception {
        try {
            // 模拟任务执行:随机睡眠1-6秒,用来测试超时(假设超时时间设为5秒)
            int sleepTime = new Random().nextInt(6) + 1;
            Thread.sleep(sleepTime * 1000);

            // 模拟任务执行失败的场景:比如Task-3固定抛出异常
            if ("Task-3".equals(taskName)) {
                throw new RuntimeException("数据库连接失败");
            }

            return taskName + " 执行完成";
        } catch (InterruptedException e) {
            // 响应线程中断:超时后线程会被中断,这里可以做清理工作
            Thread.currentThread().interrupt(); // 保留中断状态,方便上层处理
            throw e;
        }
    }

    // getter和setter方法,用于获取和设置状态、结果
    public String getTaskName() { return taskName; }
    public TaskStatus getStatus() { return status; }
    public void setStatus(TaskStatus status) { this.status = status; }
    public String getResult() { return result; }
    public void setResult(String result) { this.result = result; }
}

// 主类,演示执行流程
public class MultiTaskWithTimeout {
    public static void main(String[] args) {
        // 创建固定大小为5的线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);
        // 设置超时时间:5秒
        int timeoutSeconds = 5;
        List<Task> tasks = new ArrayList<>();

        // 初始化5个任务
        for (int i = 1; i <= 5; i++) {
            tasks.add(new Task("Task-" + i));
        }

        try {
            // 提交所有任务,等待超时时间或所有任务完成
            List<Future<String>> futures = executor.invokeAll(tasks, timeoutSeconds, TimeUnit.SECONDS);

            // 遍历每个任务,处理结果
            for (int i = 0; i < tasks.size(); i++) {
                Task task = tasks.get(i);
                Future<String> future = futures.get(i);

                try {
                    // 获取任务结果:如果任务正常完成,这里会返回结果
                    String result = future.get();
                    task.setStatus(TaskStatus.SUCCESS);
                    task.setResult(result);
                } catch (TimeoutException e) {
                    // 任务超时:超时后invokeAll会中断未完成的线程,这里标记状态为TIMEOUT
                    task.setStatus(TaskStatus.TIMEOUT);
                    task.setResult("任务超时,未完成");
                    System.out.println(task.getTaskName() + " 超时");
                } catch (ExecutionException e) {
                    // 任务执行失败:任务内部抛出异常,这里标记状态为FAILED
                    task.setStatus(TaskStatus.FAILED);
                    task.setResult("执行失败:" + e.getCause().getMessage());
                    System.out.println(task.getTaskName() + " 执行失败:" + e.getCause().getMessage());
                } catch (InterruptedException e) {
                    // 主线程被中断:这里可以根据业务需求处理
                    Thread.currentThread().interrupt();
                    task.setStatus(TaskStatus.FAILED);
                    task.setResult("线程被中断");
                }
            }

            // 输出所有任务的最终状态和结果
            System.out.println("\n=== 所有任务执行结果 ===");
            for (Task task : tasks) {
                System.out.printf("任务:%s | 状态:%s | 结果:%s%n",
                        task.getTaskName(), task.getStatus(), task.getResult());
            }

        } catch (InterruptedException e) {
            // 处理主线程被中断的情况
            Thread.currentThread().interrupt();
            System.err.println("主线程被中断,任务执行终止");
        } finally {
            // 必须关闭线程池,避免资源泄漏
            executor.shutdown();
            try {
                // 等待线程池优雅关闭,最多等1分钟
                if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
                    // 超时后强制关闭线程池
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
}

关键细节解释

  1. invokeAll()的作用:
    这个方法会一次性提交所有任务,并等待所有任务完成或者达到超时时间,超时后会自动中断未完成的线程。返回的Future集合和提交的任务是一一对应的,不管任务是否完成,你都能遍历处理。

  2. 异常与状态处理:

    • 当任务正常完成:future.get()返回任务结果,标记状态为SUCCESS
    • 当任务超时:future.get()抛出TimeoutException,标记状态为TIMEOUT
    • 当任务执行失败:任务内部抛出的异常会被包装成ExecutionException,通过e.getCause()拿到原始异常,标记状态为FAILED
  3. 线程中断的响应:
    任务里的InterruptedException要正确处理,调用Thread.currentThread().interrupt()保留中断状态,这样上层代码能感知到中断。如果你的任务是IO密集型或者循环型的,最好在代码里定期检查Thread.currentThread().isInterrupted(),及时响应中断。

  4. 线程池的关闭:
    一定要在finally块里关闭线程池,shutdown()是优雅关闭(等待已提交的任务完成),awaitTermination()用来等待关闭完成,超时后用shutdownNow()强制关闭,避免资源泄漏。

内容的提问来源于stack exchange,提问作者voidMainReturn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:23:49