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

如何让ExecutorService等待所有Future执行完成?附示例代码

如何让ExecutorService等待所有Future执行完成

嘿,我来帮你搞定这个需求!先看你的代码,其实已经用到了关键的invokeAll方法,它本身就实现了等待所有任务完成的核心逻辑,不过咱们可以再优化下细节,让代码更健壮。

核心原理:利用invokeAll的阻塞特性

ExecutorService.invokeAll()方法会一次性提交所有Callable任务,然后阻塞当前线程,直到所有任务都执行完毕(不管是正常结束还是抛出异常),之后才会返回包含所有Future的列表。这一步已经帮你完成了“等待所有Future执行完成”的核心需求。

优化后的完整代码

咱们来调整下你的代码,完善结果处理和线程池关闭的逻辑:

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

public class TaskWaitDemo {
    public static void main(String[] args) {
        try {
            // 创建固定大小的线程池
            ExecutorService executor = Executors.newFixedThreadPool(5);
            List<Callable<String>> taskList = new ArrayList<>(5);

            // 构建任务列表(给每个任务加标识方便调试)
            for (int i = 1; i <= 5; i++) {
                final int taskId = i;
                taskList.add(new SimpleTask(taskId));
            }

            // 关键:invokeAll会阻塞直到所有任务完成
            List<Future<String>> futures = executor.invokeAll(taskList);

            // 关闭线程池:不再接受新任务,已提交的任务继续执行
            executor.shutdown();

            // 等待线程池所有任务执行完毕,设置超时时间(可根据业务调整)
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                // 超时后强制关闭线程池,中断未完成的任务
                executor.shutdownNow();
                System.err.println("线程池超时强制关闭");
            }

            // 遍历所有Future,获取结果并处理可能的异常
            for (Future<String> future : futures) {
                try {
                    String result = future.get();
                    System.out.println(result);
                } catch (ExecutionException e) {
                    // 任务执行时抛出的异常会被包装在这里
                    System.err.println("任务执行失败:" + e.getCause().getMessage());
                }
            }

            System.out.println("所有任务执行完成!Exit");
        } catch (InterruptedException e) {
            // 处理等待过程中线程被中断的情况
            Thread.currentThread().interrupt();
            e.printStackTrace();
        }
    }

    // 自定义的Callable任务
    static class SimpleTask implements Callable<String> {
        private final int taskId;

        public SimpleTask(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public String call() throws Exception {
            // 模拟任务耗时操作
            Thread.sleep(1000 * taskId);
            return "任务" + taskId + "执行完成";
        }
    }
}

关键细节说明

  • invokeAll的作用:不用自己写循环判断每个Future是否完成,这个方法帮你一次性搞定等待所有任务结束。
  • shutdown() + awaitTermination():shutdown()只是禁止线程池接受新任务,已经提交的任务会继续跑;awaitTermination()会阻塞等待,确保所有任务都执行完,避免程序提前退出。如果超时还没完成,就用shutdownNow()强制中断。
  • 异常处理:每个任务执行时的异常会被包装在ExecutionException里,遍历Future的时候要逐个处理,避免漏掉某个任务的错误。

另一种写法:逐个提交任务并等待

如果你不想用invokeAll,也可以逐个提交任务,然后循环调用future.get()(这个方法会阻塞直到当前任务完成):

// 替换invokeAll部分的写法
List<Future<String>> futures = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
    final int taskId = i;
    futures.add(executor.submit(new SimpleTask(taskId)));
}

// 逐个等待任务完成并获取结果
for (Future<String> future : futures) {
    try {
        System.out.println(future.get());
    } catch (ExecutionException e) {
        System.err.println("任务执行失败:" + e.getCause().getMessage());
    }
}

这种写法和invokeAll的效果是一样的,只是invokeAll更简洁。

总结一下:你的原始代码已经走对了方向,只要补充好线程池关闭的逻辑和异常处理,就能完美实现“等待所有Future执行完成”的需求啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 02:32:51