You need to enable JavaScript to run this app. SpringBoot @RequestMapping接口的线程处理机制疑问
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot @RequestMapping接口的线程处理机制疑问

SpringBoot 默认 @RequestMapping 请求处理逻辑拆解

基础处理模型

SpringBoot 未做额外配置时,默认使用内嵌Tomcat作为Web容器,请求处理完全遵循Tomcat标准NIO线程模型,和常规并行多线程处理逻辑完全一致:

  • 独立Acceptor线程负责监听、接收新的TCP连接,将连接绑定到事件轮询队列
  • 固定规模的Worker工作线程池负责处理具体的HTTP请求,默认参数如下:
    • 最大工作线程数200
    • 最大承载TCP连接数8192
    • 工作线程全部被占用时,新连接会进入长度为100的等待队列,不会直接被拒绝
      也就是说,只要并发请求数不超过200,所有请求都会被并行处理,不存在服务端层面的串行排队逻辑。你最初预期的“5个请求同时触发sleep日志、20秒后同时结束”的并行效果,本身是完全符合服务端实际行为的。

实测日志差异的真实成因

你看到的有时间差、串行输出的日志,根源不在服务端,而在Chrome浏览器的客户端请求限制:
Chrome对同域名下的顶层导航请求(也就是在地址栏输入地址回车、触发整页加载的请求)有严格的发送队列规则:如果同域名的前一个导航请求还处于pending状态(未收到服务端响应),后续的同域导航请求会被暂存在浏览器本地队列,不会立刻向外发送。
结合你输出的日志时间线可以完全匹配这个逻辑:

  • 14:30:35 第一个标签页的请求发出,到达服务端后触发第一条sleep begin,开始20秒的线程休眠
  • 剩下4个标签页的请求,哪怕你在第一个请求等待的20秒内都按下了回车,也会被Chrome在本地压20秒,根本没发送到服务端
  • 14:30:55 第一个请求休眠结束、返回响应给浏览器,Chrome才会按照之前的点击顺序,依次把本地队列里的4个请求发出去,因为浏览器自身的请求调度间隔,就出现了55分、57分、59分、00分依次触发sleep begin的日志
  • 每个请求到达服务端后都会执行20秒休眠,所以对应的sleep end日志依次在14:31:15、14:31:17、14:31:19、14:31:20输出

可以通过两个简单测试验证这个结论:

  • 不用Chrome标签页,改用5个独立终端窗口同时执行curl http://localhost:8080/hello,会看到服务端立刻输出连续5条sleep begin,20秒后输出连续5条sleep end,完全符合最初的并行预期
  • 打开Chrome开发者工具的Network面板,可以看到后4个请求的总耗时里,有接近20秒是在浏览器本地队列等待的时间,真正到达服务端后的处理时间只有20秒

认知偏差说明

你之所以会觉得服务端的线程逻辑“既不像单线程、也不像常规并行模型”,本质是把浏览器客户端的本地排队行为,误判成了服务端的处理逻辑:服务端从始至终都是按多线程并行的规则处理到达的请求,所有的串行延迟都是浏览器侧的调度限制导致的,和@RequestMapping的映射处理逻辑没有关联。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 04:36:08