使用invokeAll可批量提交Callable任务并获取有序结果,适合需等待所有任务完成的场景;也可通过submit逐个提交任务以灵活控制执行流程;为避免阻塞应设置超时时间;最后需调用shutdown和awaitTermination确保线程池安全关闭。

在Java中,ExecutorService 是并发编程中非常重要的工具,它能有效管理线程池并执行多个任务。当你需要批量执行任务时,可以通过 ExecutorService 提交多个任务,并等待它们完成。以下是实现批量任务执行的常用方式和关键步骤。
使用 invokeAll 批量提交任务
最直接的方式是使用 invokeAll(Collection<Callable<T>> tasks) 方法,它可以一次性提交多个 Callable 任务,并返回每个任务的 Future 结果列表。
- 所有任务会并行执行,方法会阻塞直到所有任务完成。
- 返回的 Future 列表顺序与输入的任务集合顺序一致。
- 适合需要获取每个任务返回结果的场景。
示例代码:
ExecutorService executor = Executors.newFixedThreadPool(4);
<p>List<Callable<String>> tasks = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
final int taskId = i;
tasks.add(() -> {
Thread.sleep(1000);
return "任务 " + taskId + " 完成";
});
}</p><p>try {
List<Future<String>> results = executor.invokeAll(tasks);
for (Future<String> result : results) {
System.out.println(result.get()); // 输出每个任务的结果
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
使用 submit 提交多个任务并手动收集 Future
如果你希望更灵活地控制任务提交过程,可以逐个调用 submit() 方法,并将返回的 Future 存入集合中,之后统一处理结果。
立即学习“Java免费学习笔记(深入)”;
- 可以混合使用 Runnable 和 Callable 任务。
- 支持异步处理或部分任务超时控制。
- 适用于任务数量动态变化或需差异化处理的场景。
示例代码:
ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<Integer>> futures = new ArrayList<>();
<p>for (int i = 0; i < 5; i++) {
final int job = i;
Future<Integer> future = executor.submit(() -> {
return job * job;
});
futures.add(future);
}</p><p>// 获取结果
for (Future<Integer> f : futures) {
try {
System.out.println("结果: " + f.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
设置超时限制避免无限等待
在生产环境中,长时间阻塞可能影响系统稳定性。你可以为 invokeAll 设置超时时间,防止某些任务卡住。
示例:带超时的批量执行
List<Future<String>> results = executor.invokeAll(tasks, 3, TimeUnit.SECONDS);
- 如果在指定时间内未完成所有任务,未完成的任务对应的 Future 调用
get()会抛出 TimeoutException。 - 可以根据业务需求决定是否取消这些任务(
future.cancel(true))。
合理关闭线程池
任务执行完成后,必须调用 shutdown() 并配合 awaitTermination() 确保资源释放。
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 强制关闭
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
基本上就这些。通过 ExecutorService 实现批量任务执行,关键是选择合适的方法提交任务、妥善处理结果与异常,并正确管理线程生命周期。不复杂但容易忽略细节。










