能否多次调用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
相关产品推荐
相关产品推荐

