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

Java Executor Service如何等待所有任务执行完成?

如何等待ExecutorService的所有任务执行完成?

我使用Executor Service同时运行10个任务,每次执行2个任务,代码如下:

ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; i++) {
    String name = "NamePrinter " + i;
    Runnable runner = new TaskPrint(name, 1000);
    System.out.println("Adding: " + name + " / " + 1000);
    executor.execute(runner);
}

请问如何等待所有任务执行完成?

这里有几种可靠的方法可以实现需求,你可以根据场景选择最合适的:

方法一:使用shutdown() + awaitTermination()(推荐)

这是最标准、最常用的做法,步骤清晰且符合ExecutorService的设计规范:先关闭服务不再接收新任务,再等待已提交的任务全部执行完毕。

executor.shutdown(); // 停止接收新任务,已提交的任务会继续执行
try {
    // 等待所有任务完成,这里设置1小时超时,可根据任务实际耗时调整
    if (!executor.awaitTermination(1, TimeUnit.HOURS)) {
        // 超时未完成时,强制中断剩余任务
        executor.shutdownNow();
        // 再等待一段时间,确保中断后的任务能收尾
        if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
            System.err.println("ExecutorService 未能正常终止");
        }
    }
} catch (InterruptedException e) {
    // 当前线程被中断时,同步中断Executor的所有任务
    executor.shutdownNow();
    // 保留当前线程的中断状态,交给上层逻辑处理
    Thread.currentThread().interrupt();
}

方法二:使用invokeAll()

如果可以提前把所有任务收集成Callable列表,invokeAll()会直接阻塞主线程,直到所有任务完成或超时。对于你的Runnable任务,用Executors.callable()就能轻松转换:

List<Callable<Void>> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    String name = "NamePrinter " + i;
    Runnable runner = new TaskPrint(name, 1000);
    System.out.println("Adding: " + name + " / " + 1000);
    tasks.add(Executors.callable(runner));
}

ExecutorService executor = Executors.newFixedThreadPool(2);
try {
    // 阻塞直到所有任务完成,或超过1小时超时
    executor.invokeAll(tasks, 1, TimeUnit.HOURS);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} finally {
    executor.shutdown();
}

方法三:使用CountDownLatch

如果需要更灵活的多线程同步控制(比如多个线程等待同一批任务完成),CountDownLatch是很好的选择。初始化计数器为任务总数,每个任务执行完毕后调用countDown(),主线程通过await()等待计数器归0:

CountDownLatch latch = new CountDownLatch(10); // 任务总数为10
ExecutorService executor = Executors.newFixedThreadPool(2);

for (int i = 0; i < 10; i++) {
    String name = "NamePrinter " + i;
    Runnable runner = new Runnable() {
        @Override
        public void run() {
            try {
                new TaskPrint(name, 1000).run();
            } finally {
                latch.countDown(); // 任务完成,计数器减1
            }
        }
    };
    System.out.println("Adding: " + name + " / " + 1000);
    executor.execute(runner);
}

try {
    latch.await(); // 等待所有任务完成,计数器变为0
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} finally {
    executor.shutdown();
}

选择建议

  • 优先用方法一,它是ExecutorService的标准终止流程,简洁安全,覆盖了大部分常规场景。
  • 如果一开始就能收集所有任务,方法二的代码会更直观。
  • 方法三适合复杂的多线程同步场景,比如需要多个线程等待同一批任务结束后再执行后续逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:02:36