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

为何需要异步Servlet?基于Spring Boot嵌入式Tomcat8的MVC场景问询

Spring Boot + 嵌入式Tomcat 8 阻塞API的线程优化方案

作为一直在Spring Boot MVC项目里摸爬滚打的开发者,你提到的这个痛点我太熟悉了——Tomcat连接池里的线程被阻塞API死死占着,啥也干不了只能等,结果就是后续请求排队,系统吞吐量直接拉胯。不过好在Spring给我们提供了Callable和DeferredResult这两个神器,能完美解决这个问题,我给你详细唠唠:

核心逻辑:把阻塞任务从Tomcat线程转移出去

不管用哪种方式,核心思路都是让Tomcat的请求线程尽早释放回连接池,把耗时的阻塞操作交给我们自己管控的线程池去处理,这样Tomcat线程就能去处理更多请求,提升并发能力。

1. 使用Callable处理同步阻塞场景

如果你的业务是「先做少量同步操作,再调用阻塞API,最后返回结果」,Callable是最省心的选择。它会自动把阻塞逻辑提交到你配置的ExecutorService线程池里执行,Tomcat线程不用等阻塞完成就能先回去干活。

举个简单的代码示例:

@GetMapping("/async-callable")
public Callable<String> handleAsyncRequest() {
    return () -> {
        // 这里替换成你的阻塞API调用,比如远程接口调用、慢SQL查询
        Thread.sleep(5000); // 模拟5秒阻塞操作
        return "Callable异步处理完成!";
    };
}
  • 如果你没有自定义ExecutorService作为Bean,Spring会默认使用Tomcat的异步线程池,或者为每个请求创建新线程(这很危险,容易OOM),所以一定要自己配置线程池Bean,比如:
@Bean
public ExecutorService customAsyncExecutor() {
    return new ThreadPoolExecutor(
        4, // 核心线程数
        8, // 最大线程数
        60L, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(100),
        new ThreadFactoryBuilder().setNameFormat("async-pool-%d").build()
    );
}

2. 使用DeferredResult处理异步事件驱动场景

如果你的业务需要等待某个异步事件(比如消息队列的回调、第三方Webhook通知)才能返回结果,DeferredResult就更合适了。它允许你先把请求挂起,释放Tomcat线程,等异步结果就绪后再唤醒请求并返回响应。

代码示例:

@GetMapping("/async-deferred")
public DeferredResult<String> handleDeferredRequest() {
    // 设置60秒超时,避免请求无限挂起
    DeferredResult<String> deferredResult = new DeferredResult<>(60000L);

    // 用自定义线程池执行异步任务
    customAsyncExecutor.execute(() -> {
        try {
            // 模拟等待异步事件(比如监听MQ消息)
            Thread.sleep(5000);
            // 结果就绪,返回响应
            deferredResult.setResult("DeferredResult异步处理完成!");
        } catch (InterruptedException e) {
            // 处理异常或超时
            deferredResult.setErrorResult("处理超时或发生错误");
        }
    });

    return deferredResult;
}

这里一定要记得设置超时时间,不然如果异步任务一直没结果,请求会一直占用资源。

关键注意点

  • 自定义线程池时,要根据你的业务场景和服务器配置合理设置参数(核心线程数、最大线程数、队列大小),避免线程过多导致CPU上下文切换频繁,或者队列过大导致内存溢出。
  • 不管用Callable还是DeferredResult,都要做好异常处理和超时控制,避免出现请求挂死或者资源泄漏的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:22:12