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

SpringBoot 3.4启用虚拟线程却串行执行的问题排查

问题原因及解决方案

为什么会出现串行执行、线程名是Tomcat线程的情况?

  1. 虚拟线程不会自动“接管”同步代码
    你配置的spring.threads.virtual.enabled=true只是让Spring内置的任务执行器默认使用虚拟线程,但HTTP请求的入口仍然由Tomcat的平台线程(tomcat-handler-xxx)处理。你代码里是同步调用generateExpression(),这些代码会直接在Tomcat线程上串行执行,不会自动切换到虚拟线程。

  2. 同步RestClient调用阻塞了当前线程
    generateExpression()里的RestClient调用是同步阻塞式的,会一直占用Tomcat线程直到请求返回,完全没有触发虚拟线程的调度机制。

  3. Tomcat默认未启用虚拟线程处理请求
    要让Tomcat用虚拟线程处理HTTP请求,需要额外添加配置:

    server.tomcat.threads.virtual.enabled=true
    

    但就算开启了这个配置,同步调用的代码依然会串行执行,只是请求处理线程换成虚拟线程而已。

怎么实现并行结构化并发?

正如你提到的,必须用StructuredTaskScope来主动创建虚拟线程并行执行任务,修正后的代码示例:

public String testFlow() {
    final Instant start = Instant.now();
    // 用StructuredTaskScope管理虚拟线程任务,ShutdownOnFailure表示任一任务失败就终止所有
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        // 并行提交三个生成表达式的任务
        Supplier<String> expressionTask = scope.fork(this::generateExpression);
        Supplier<String> dummy1Task = scope.fork(this::generateExpression);
        Supplier<String> dummy2Task = scope.fork(this::generateExpression);

        // 等待所有任务完成,若有失败直接抛出异常
        scope.join();
        scope.throwIfFailed();

        // 获取三个任务的结果
        String expression = expressionTask.get();
        String dummy1 = dummy1Task.get();
        String dummy2 = dummy2Task.get();

        log.info("Generated expression: {}", expression);
        // 后续业务逻辑...
    } catch (InterruptedException | ExecutionException e) {
        throw new RuntimeException("并行任务执行失败", e);
    }
    // 计算耗时等逻辑...
}

额外说明

  • StructuredTaskScope是Java21原生的结构化并发API,能保证子任务和父任务生命周期绑定,避免线程泄露,是实现虚拟线程并行的推荐方式。
  • 若不想用原生API,也可以使用Spring的@Async注解,Spring Boot3.4开启虚拟线程开关后,@Async默认会使用虚拟线程池,但结构化并发的可靠性和可读性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 19:03:13