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

能否多次调用SingleThreadExecutor#submit()?并行代码停滞排查

问题分析与解决方案

核心停滞原因:SingleThreadExecutor嵌套提交导致死锁

你当前的代码陷入停滞,根源在于SingleThreadExecutor的线程被阻塞,同时新提交的任务无法获得线程执行:

每个循环创建的SingleThreadExecutor只有1个工作线程。当runAsync的任务在这个线程上执行时,调用getStringList并向同一个executor提交新任务,随后调用stringListFuture.get()——此时当前线程会被阻塞,等待新任务完成。但这个新任务被放进了SingleThreadExecutor的任务队列,而唯一的线程正被阻塞的runAsync任务占用,新任务永远无法执行,最终形成死锁,程序停滞。

正确实现方式

方案1:单线程内同步执行所有步骤(符合你的需求)

既然你需要每个代码块像同步代码一样在独立线程运行,完全不需要在内部嵌套调用executor.submit()。直接在runAsync的任务中按顺序同步执行所有逻辑,整个代码块会在SingleThreadExecutor的独立线程上完成,既保证步骤顺序,又实现多实例并行。

修改后代码示例:

ArrayList<CompletableFuture<Void>> futures = new ArrayList<>();

for (int i = 0; i < SIZE; i++) {
    ExecutorService executor = Executors.newSingleThreadExecutor();

    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        try {
            // 同步获取double数据
            Double doubleData = doubleDataService.getFuture().get();
            // 同步执行Retrofit请求
            Call<List<String>> stringCall = retrofit.create(Api.class).getData(doubleData);
            List<String> stringList = stringCall.execute().body();

            // 同步执行后续请求
            Integer integerData = myIntegerService.getInteger();

            // 这里添加后续业务逻辑
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }, executor);

    futures.add(future);
}

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// 所有并行任务完成后的操作

方案2:使用固定线程池简化资源管理

如果不想创建大量SingleThreadExecutor,可以提前创建一个固定大小的线程池,将每个代码块的任务提交到池中。每个任务会被分配到池中的独立线程,内部同步执行步骤,同样满足需求:

// 根据并行数量创建固定大小线程池
ExecutorService executorPool = Executors.newFixedThreadPool(SIZE);

ArrayList<CompletableFuture<Void>> futures = new ArrayList<>();

for (int i = 0; i < SIZE; i++) {
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        try {
            Double doubleData = doubleDataService.getFuture().get();
            Call<List<String>> stringCall = retrofit.create(Api.class).getData(doubleData);
            List<String> stringList = stringCall.execute().body();

            Integer integerData = myIntegerService.getInteger();

            // 后续业务逻辑
        } catch (Exception e) {
            e.printStackTrace();
        }
    }, executorPool);

    futures.add(future);
}

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
executorPool.shutdown();
// 所有任务完成后的操作

关键结论

  • 绝对不能在SingleThreadExecutor的工作线程内部,向同一个执行器提交任务并调用Future.get(),这必然引发死锁。
  • 要实现“每个代码块如同同步代码但多实例并行”,只需让代码块的所有步骤在独立线程中同步执行,无需嵌套使用执行器提交任务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:43:12