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

Java:如何并行执行多个Runnable并超时终止长运行任务?

单个任务独立超时的线程池实现方案

要实现每个任务独立5秒超时(而非全局总超时),同时避免主线程阻塞,可通过以下思路解决:

  1. 单独提交任务并关联ID与Future:放弃invokeAll的全局超时机制,逐个提交任务到线程池,用Map记录每个任务ID对应的Future对象。
  2. 异步定时监控超时:借助ScheduledExecutorService为每个任务安排5秒后的延迟检查,若任务未完成则取消并记录ID。
  3. 处理任务取消逻辑:任务被中断时捕获InterruptedException,在任务内部标记超时状态,主线程统一收集超时任务ID。

修改后的代码示例:

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

public class TestExecutorService {
    // 核心线程数匹配CPU核心数,满足并行执行需求
    private static final ExecutorService taskExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    private static final ScheduledExecutorService timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
    private static final List<Integer> timeoutTaskIds = new CopyOnWriteArrayList<>();

    public static void main(String[] args) throws InterruptedException {
        Map<Integer, Future<?>> taskFutureMap = new HashMap<>();

        for (int i = 0; i < 100; i++) {
            int taskId = i;
            int minSleep = 1;
            int maxSleep = 10;

            Runnable task = () -> {
                try {
                    int sleepTime = minSleep + (int) (Math.random() * ((maxSleep - minSleep) + 1));
                    System.out.printf("## 任务ID: %d 预计耗时: %d 秒%n", taskId, sleepTime);
                    Thread.sleep(sleepTime * 1000);
                    System.out.printf("## 任务ID: %d 正常完成,耗时: %d 秒%n", taskId, sleepTime);
                } catch (InterruptedException e) {
                    System.out.printf("## 任务ID: %d 因超时被终止%n", taskId);
                    timeoutTaskIds.add(taskId);
                }
            };

            // 提交任务并保存Future与任务ID的映射
            Future<?> future = taskExecutor.submit(task);
            taskFutureMap.put(taskId, future);

            // 安排5秒后的定时任务,检查并取消未完成任务
            timeoutExecutor.schedule(() -> {
                Future<?> f = taskFutureMap.get(taskId);
                if (f != null && !f.isDone()) {
                    // 中断正在运行的任务
                    f.cancel(true);
                }
            }, 5, TimeUnit.SECONDS);
        }

        // 关闭任务线程池,等待所有任务完成
        taskExecutor.shutdown();
        taskExecutor.awaitTermination(20, TimeUnit.SECONDS);
        // 关闭定时监控线程池
        timeoutExecutor.shutdown();

        // 输出超时任务列表
        System.out.println("=====================");
        System.out.println("超时被终止的任务ID列表:");
        timeoutTaskIds.forEach(id -> System.out.print(id + " "));
    }
}

关键逻辑说明:

  • 线程池配置:taskExecutor核心线程数与CPU核心数一致,符合"4个CPU同时运行4个任务"的并行要求。
  • 无阻塞监控:timeoutExecutor作为单线程定时池,异步处理每个任务的超时检查,不会阻塞主线程。
  • 任务中断处理:Future.cancel(true)会中断任务的睡眠操作,触发InterruptedException,任务内部捕获后记录超时ID。
  • 线程安全存储:使用CopyOnWriteArrayList存储超时任务ID,避免多线程写入时的并发冲突。

内容的提问来源于stack exchange,提问作者Bằng Rikimaru

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:00:19