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

多线程问题:线程完成后获取执行结果

问题分析与解决方案

你的代码核心问题在于主线程和Worker线程的执行完全不同步,这直接导致了array为空:

  • 当你调用pool.execute(littleDwarfWorker)时,只是把任务丢给线程池去排队或执行,主线程会立刻跳去执行finally块——这时候Worker的run()方法可能还没开始跑,甚至还在排队,getResult()自然拿不到任何有效结果。
  • 更关键的是:你的finally块属于主线程的for循环迭代逻辑,和Worker线程的生命周期半毛钱关系都没有,它根本不会等Worker跑完再执行。

下面给你两种靠谱的解决方案,优先推荐第一种,更符合Java多线程的规范用法。


方案一:改用Callable+Future获取异步结果

如果你能修改LittleDwarfWorker的代码,把它从Runnable改成Callable是最优解——因为Callable允许你返回任务执行结果,而ExecutorService.submit()会返回一个Future对象,帮你跟踪任务状态、获取结果。

第一步:修改LittleDwarfWorker实现Callable

把run()换成call()方法,直接返回你的数据库查询结果(把YourResultType换成你实际返回的类型,比如String、自定义POJO等):

public class LittleDwarfWorker implements Callable<YourResultType> {
    private DataSource dataSource;
    // 其他需要的参数

    // 构造器,传入dataSource和其他参数
    public LittleDwarfWorker(DataSource dataSource, ...) {
        this.dataSource = dataSource;
        // 初始化其他参数
    }

    @Override
    public YourResultType call() throws Exception {
        JdbcTemplate localJdbcTemplate = new JdbcTemplate(this.dataSource);
        // 执行数据库查询,拿到结果
        YourResultType result = ...; // 这里写你的查询逻辑
        return result;
    }
}

第二步:修改主线程代码,用submit()收集Future并获取结果

先把所有任务的Future收集起来,等所有任务都提交后,再逐个获取结果:

List<YourResultType> array = new ArrayList<>();
int i = 0;
ExecutorService pool = Executors.newFixedThreadPool(50);
// 用来保存所有任务的Future对象
List<Future<YourResultType>> futures = new ArrayList<>();

for(String str : strList) { 
    LittleDwarfWorker littleDwarfWorker = new LittleDwarfWorker(dataSource, ...); 
    try { 
        // 用submit提交任务,拿到Future
        Future<YourResultType> future = pool.submit(littleDwarfWorker);
        futures.add(future);
    } catch(Exception e) { 
        e.printStackTrace(); 
    } finally { 
        i++;
        if((i % 100) == 0) { 
            log.info("Progression :" + i + "/" + strList.size()); 
        } 
    } 
} 

// 等待所有任务完成,收集结果
for(Future<YourResultType> future : futures) {
    try {
        // get()方法会阻塞主线程,直到对应任务完成并返回结果
        YourResultType result = future.get();
        if(result != null) {
            array.add(result);
        }
    } catch(InterruptedException | ExecutionException e) {
        // 捕获任务执行中的异常
        e.printStackTrace();
    }
}

// 关闭线程池
pool.shutdown();
// 可选:等待线程池完全关闭,避免程序提前退出
if(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
    pool.shutdownNow();
}

这种方式的好处:

  • 能精准控制结果的获取时机,确保拿到的是Worker执行完成后的有效结果。
  • 可以通过Future捕获任务执行过程中抛出的异常,排查问题更方便。
  • 代码逻辑清晰,符合Java并发编程的最佳实践。

方案二:如果不能修改Worker的run()方法,让Worker主动添加结果

如果因为历史代码依赖,不能把Runnable改成Callable,那可以让Worker在任务完成后,主动把结果加到集合里——但一定要注意集合的线程安全!

第一步:用线程安全的集合

因为多个Worker线程会同时修改集合,普通的ArrayList会有并发问题,所以要用Collections.synchronizedList或者CopyOnWriteArrayList:

// 用线程安全的ArrayList
List<Object> array = Collections.synchronizedList(new ArrayList<>()); 
int i = 0;
ExecutorService pool = Executors.newFixedThreadPool(50); 

第二步:修改Worker的构造器和run()方法

把线程安全的集合传给Worker,让它在任务完成后主动添加结果:

public class LittleDwarfWorker implements Runnable {
    private DataSource dataSource;
    private List<Object> resultList;

    // 构造器传入dataSource和结果集合
    public LittleDwarfWorker(DataSource dataSource, List<Object> resultList) {
        this.dataSource = dataSource;
        this.resultList = resultList;
    }

    @Override
    public void run() { 
        JdbcTemplate localJdbcTemplate = new JdbcTemplate(this.dataSource); 
        // 执行数据库查询,拿到结果
        Object result = ...; 
        // 任务完成后,把结果加入线程安全的集合
        resultList.add(result);
    }
}

第三步:主线程等待所有任务完成

主线程提交完所有任务后,必须等待线程池里的所有任务都执行完,才能去使用array:

for(String str : strList) { 
    LittleDwarfWorker littleDwarfWorker = new LittleDwarfWorker(dataSource, array); 
    try { 
        pool.execute(littleDwarfWorker); 
    } catch(Exception e) { 
        e.printStackTrace(); 
    } finally { 
        i++;
        if((i % 100) == 0) { 
            log.info("Progression :" + i + "/" + strList.size()); 
        } 
    } 
} 

// 关闭线程池并等待所有任务完成
pool.shutdown();
if(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
    pool.shutdownNow();
}

// 现在array里就有所有Worker的结果了

这种方式的注意点:

  • 必须使用线程安全的集合,否则会出现数据丢失、数组越界等并发异常。
  • 主线程一定要等待线程池任务全部完成,否则array里的结果可能不全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:13:45