ExecutorService.invokeAll() 同步等待全部 Callable 任务完成,返回按提交顺序排列的 Future 列表;无界版本无限等待并可能因中断抛 InterruptedException,超时版本超时后未完成任务被取消且对应位置为 null;需逐个调用 get() 获取结果或异常,单任务异常不影响其余任务执行。

ExecutorService.invokeAll() 是 Java 并发包中用于批量提交 Callable 任务并**同步等待全部完成**的核心方法。它本身会阻塞当前线程,直到所有任务结束(正常返回或抛出异常),且能完整保留每个任务的执行结果(包括异常封装),无需额外同步控制。
阻塞行为:明确超时与无界等待的区别
该方法有两个重载版本:
-
invokeAll(Collection<? extends Callable<T>> tasks):无限期等待,任一任务被中断或线程被中断都会导致整个调用提前抛出InterruptedException;所有未完成任务会被取消(但不保证立即停止)。 -
invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit):最多等待指定时长;超时后未完成的任务将被取消,已返回的结果仍保留在返回列表中,对应超时任务的位置为null(注意不是Future.get()抛异常)。
结果捕获:每个 Future 都封装了任务终态
返回值是 List<Future<T>>,顺序与任务提交顺序严格一致。对每个 Future 调用 get() 时:
- 若任务正常完成 → 返回计算结果;
- 若任务抛出异常 →
get()抛出ExecutionException,其getCause()即原始异常(如NullPointerException); - 若任务被取消(如超时或手动取消)→
get()抛出CancellationException。
这意味着你必须显式遍历结果列表并逐个调用 get() 才能获取实际结果或捕获异常——invokeAll() 本身不会把异常“抛出来”,只是把带状态的 Future 组织好交给你处理。
异常任务不影响其他任务执行
一个任务内部抛出未捕获异常,只会导致其对应的 Future 在 get() 时包装为 ExecutionException,**不会中断其他任务运行**,也不会影响 invokeAll() 的返回时机。所有任务仍会继续执行至完成、取消或超时。因此,它天然支持“尽力而为”的批量执行语义。
实用建议:避免常见误用
- 不要在
invokeAll()后直接强转或假设结果非空——需检查future.isDone()和future.isCancelled()再调用get(); - 超时版本中,即使部分任务超时,也要遍历整个结果列表,跳过
null位置即可; - 若需统一失败策略(如任一失败则整体回滚),应在获取全部
Future后自行判断,而不是依赖invokeAll()抛异常; - 注意线程池拒绝策略:若提交时队列已满,
invokeAll()会在第一个任务提交失败时就抛出RejectedExecutionException,后续任务根本不会进入队列。
不复杂但容易忽略:它的“阻塞”是可控的,“异常”是封装的,“并发”是独立的——关键在于理解它返回的是“已完成任务的句柄集合”,而非“执行结果集合”。

















