先讲为什么:DeferredResult可以提升Servelt容器工作线程池的复用率。同时,也没有改变Servelt容器的最大物理连接数。如果新请求超过Servelt容器的最大连接,会报错:HTTP connect timed out。

Tomcat容器最多能同时处理2个请求,
即使用了DeferredResult,后面的所有请求仍然会timed out。
源码见下
同时DeferredResult有增加系统负载的风险,如何使用要提前做好评估。是不是感觉与Service层方法加@Async的效果相同?是的,都是在优化worker线程利用率。不过@Async会多出往异步线程池中“任务提交动作完成”的耗时,一旦提交成功会同时释放worker线程和Connections连接,更彻底。
是的,你没有看错,DeferredResult就只有这个作用。
来回应下常见的疑问:
是否能提升吞吐量?
是否能提升QPS?
标准的回答是:不确定,要看情况。
大概率是可以提升系统吞吐量的。
大概率是可以提升系统QPS的。
为什么?
场景1:如果请求进来的都是DeferredResult的慢请求,系统吞吐量和系统QPS都不会提升。
场景2:如果DeferredResult的慢请求不多,DeferredResult是可以提升其它轻量级接口的QPS的。如果没有DeferredResult,Servlet容器中的工作线程都被占用,这些接口也会能阻塞等待,QPS自然就降低,系统吞吐量自然就下降。
上面讲的“提升线程池的复用率”,到底是提升哪些线程的复用率。线程池很多,有点乱。。。
好问题,一个请求进来,经过的线程池真的很多。
以常见的Tomcat为例,来一块看看这个线程池:

就是这个max-threads
Spring Boot中配置会略有不同,在3.3.5中工作线程数配置如下:

server.tomcat.max-connections: 设置连接器的最大连接数。
server.tomcat.accept-count: 设置连接器的接受队列长度,即当所有工作线程都被占用时,可以接受的并发请求数量。
server.tomcat.threads.max: 设置连接器的工作线程(线程池)的最大线程数。
server.tomcat.threads.min-spare: 设置连接器的工作线程(线程池)的最小空闲线程数。
有点感觉了没?下面我们来全视角、全链路地看一下这个线程池的位置。
仍然以Tomcat为例:

有两部分:Servlet容器的连接器、处理业务的Servlet容器。

图中的线程池(Executor)就是DeferredResult提升复用率的那个!

图中的Worker线程(max-threads工作线程)
就是DeferredResult提升复用率的那个!
上面看着是不是有些乱,下面汇总一下:
一、它主要解决什么问题 DeferredResult 的核心作用,是提升Servelt容器工作线程池的复用率,是把控制器中耗时的业务计算移到独立的用户自定义的线程池中异步执行,从而让负责接收请求的容器线程立刻释放、返回。
这样做有两个明显的好处:
关键要明确:它的价值在于释放 Servlet 工作线程,提升了利用率,而不是提升系统的连接接纳能力。
二、为什么它有效(从请求链路看) 要理解 DeferredResult,得先回顾 Tomcat 处理请求的几个关键配置:
max-connections:限制同时持有的连接数;threads.max:工作线程数上限;accept-count:工作线程全忙时,请求排队的队列长度。一个常见的容量直觉是:系统真正能同时处理的请求数,约等于 min(max-connections, threads.max),accept-count 只是队列缓冲。
容量评估实践:一个Tomcat最多能同时处理多少个HTTP请求?
在同步模型下,工作线程一旦进入控制器并执行耗时操作(如 sleep、IO、RPC),在该请求完成之前,这个线程一直被占用,无法响应其他请求。
而使用 DeferredResult:
这里必须澄清它的边界:
三、结合代码与测试验证 我们通过实际代码来看实现与效果。
https://github.com/helloworldtang/spring-boot-study
代码入口(可对照项目定位)
/sync/process
对应 AsyncDemoController.java:25,业务阻塞在 :29。/async/process
对应 AsyncDemoController.java:35。:41 创建,:43 设置超时回调,:48 错误处理。:53,完成日志在 :58。:68(直接 return)。线程池配置
独立任务池在 TaskConfig.java:11 定义(ThreadPoolTaskExecutor)。
关键配置(application.yml)
server:
port: 8080
tomcat:
threads:
max: 2
min-spare: 1
max-connections: 5
accept-count: 1日志中增加了类名、行号与 X-Request-Id 跟踪(:15)。
并发对比测试 线程数限制为 2,模拟 4 个并发请求,每个耗时约 1.5 秒:
AsyncDemoIntegrationTest.java:58):76)结果说明:DeferredResult 快速释放工作线程,后台池并行执行,同一批请求完成更快。
连接数严苛场景测试
设置 max-connections=2、accept-count=1,模拟 30 个请求(客户端连接超时 200ms):
StrictConnectionLimitsTest.java:94 及统计行 :101):31 与 :59)结论再次印证:DeferredResult 不改变连接占用周期,不提升连接接纳能力;一旦连接或队列饱和,仅靠控制器异步化无法显著提升 QPS。
四、工程落地建议
容器层配置
max-connections、accept-count,避免连接阶段成为瓶颈;server.tomcat.connection-timeout;threads.max 与 min-spare-threads 足够,让请求接入与响应写回有可用线程。业务层实现
onTimeout / onError 回调,结合 X-Request-Id、类名与行号打通全链路日志;五、一句话总结 DeferredResult 的真正价值,在于释放控制器线程、让慢任务并行化,从而提高线程利用率与系统在负载内的处理效率。但它并不突破连接、队列、网络 I/O 等底层约束。要想整体提升吞吐,必须同步优化连接容量、线程池配置以及外部依赖的承载能力。