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

Java多线程中Callable任务未完成即执行createCSV的解决方法

问题根源

你的代码里最核心的问题是任务列表tasks没有在每个a和b的循环组合前重新初始化,导致每次迭代都会累积之前的任务。这会让invokeAll处理混合的任务集合,同时createCSV会处理所有历史任务的结果,造成“任务没完成就执行createCSV”的错觉——实际上要么是旧任务的进度干扰了判断,要么是重复处理导致逻辑混乱。

另外要明确:executor.invokeAll(tasks)本身会等待所有提交的任务完成后才返回,只要任务列表是当前批次的,createCSV肯定是在所有calculateRows跑完之后才执行的。

修复步骤

  1. 每个a/b循环内单独初始化任务列表
    把tasks的定义放到for (double b : listB)循环内部,确保每个a和b的组合对应独立的任务集合,不会和之前的任务混在一起。

  2. 替换无效的空等待循环
    原代码里while (!executor.isTerminated()) {}是纯空循环,会浪费CPU资源,换成带超时的等待方法更合理。

修复后的核心代码

public static void main(String[] args) {
    final int MAX_THREADS = 2;
    ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);

    for (int a : listA) {
        for (double b : listB) {
            // 每次a/b组合都新建任务列表,避免累积旧任务
            List<Callable<RowEarnings>> tasks = new ArrayList<>();
            
            for (int c : listC) {
                for (int d : listD) {
                    for (int e : listE) {
                        for (int f : listF) {
                            for (double g : listG) {
                                for (double h : listH) {
                                    for (double i : listI) {
                                        if (i < h) {
                                            try {
                                                Callable<RowEarnings> task = () -> calculateRows("C://CSV", a, b, c, d, e, f, g, h, i);
                                                tasks.add(task);
                                            } catch (Exception e) {
                                                System.out.println("Error Message");
                                                e.printStackTrace();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            
            try {
                // invokeAll会等当前tasks里所有任务全跑完才返回结果列表
                List<Future<RowEarnings>> results = executor.invokeAll(tasks);
                // 到这一步所有calculateRows都已完成,放心执行createCSV
                createCSV(directory, results, a, b);
            } catch (InterruptedException e) {
                System.out.println("Error while invoking tasks.");
                e.printStackTrace();
            }
        }
    }

    executor.shutdown();
    try {
        // 替换空循环为带超时的等待,超时后强制关闭线程池
        if (!executor.awaitTermination(1, TimeUnit.HOURS)) {
            executor.shutdownNow();
        }
        System.out.println("TEST COMPLETE");
    } catch (InterruptedException e) {
        System.out.println("Thread execution interrupted.");
        executor.shutdownNow();
        Thread.currentThread().interrupt();
    }
}

额外优化建议

  • 任务分批处理:如果任务量达到百万级,一次性提交所有任务可能占满内存,可以把任务拆成多批,每批执行完就写入部分数据(不过你的逻辑是按a/b生成单独CSV,可根据实际情况调整)。
  • 调整线程池大小:别硬写死2个线程,用Runtime.getRuntime().availableProcessors()获取CPU核心数来设置,避免线程过多导致上下文切换浪费资源。
  • 加进度日志:在calculateRows里加个计数,或者提交任务后打印当前批次的任务总数,方便你跟踪真实进度,不会再误判任务完成情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:55:23