不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2022-05-22 01:39:02  修改时间:2024-04-25 00:35:28  分类:Java框架/系统  编辑

Spring Boot中线程的维护是由servlet容器或Netty负责,所以题主应该问的是servlet容器的线程模型。而Spring Boot是一个自动配置的框架。目前Spring Boot对web开发目前有两种解决方案:

  1. 传统的web框架基于Spring MVC + Tomcat;
  2. Spring 5新增的web-reactive框架基于Spring Webflux + Netty;

这两个框架都支持大家熟用的注释,比如@Controller。技术栈可以看官网图:

先不谈web-reactive,通过分析Spring MVC和Tomcat的交互,来浅析一下Spring与servlet容器交互的原理——Spring MVC基于Java EE的Servlet API,Servlet API定义了Servlet容器和具体的servlet代码交互的约定,Spring MVC通过注册一个名为DispatcherServlet的servlet到servlet容器中处理请求,并把实际工作交给Spring提供的组件bean执行。

了解了Spring和servlet容器的交互之后再回到问题。

(1) 首先,这里强调一下连接(TCP)是传输层的,请求(HTTP)是应用层的。

在像 HTTP 这样的Client-Server协议中,会话分为三个阶段:

  1. 客户端建立一条 TCP 连接(如果传输层不是 TCP,也可以是其他适合的连接)。
  2. 客户端发送请求并等待应答。
  3. 服务器处理请求并送回应答,回应包括一个状态码和对应的数据。

从 HTTP/1.1 开始,连接在完成第三阶段后不再关闭,客户端可以再次发起新的请求。这意味着第二步和第三步可以连续进行数次。

(2) 其次真的是一个线程处理一个HTTP请求吗?我觉得这个说法也不准确。

Tomcat支持三种运行模式(BIO, NIO, APR),大致流程均是:

当客户端向服务器建立TCP连接,发送请求,服务器操作系统将该连接放入accept队列,Tomcat在accept队列中接收连接;在连接中获取请求的数据,生成request;调用servlet容器处理请求;返回response,完成一次HTTP会话。

在Tomcat 8.0前默认使用BIO,Tomcat在accept队列中接受TCP连接并获得HTTP Request,从线程池中取出空闲的线程来处理请求,如果无空闲线程则阻塞。

Tomcat 8.0起默认启用NIO模式,在从accept获得request之后,注册到nio.Selector中后不阻塞继续获取连接,Tomcat遍历找到selector中可用的request,再从线程池中取出空闲的线程来处理请求。Tomcat相关的配置参数有:

  1. acceptCount,当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。
  2. maxConnections,当Tomcat接收的连接数达到maxConnections时,accept队列中的线程会一直阻塞着。
  3. maxThreads,线程池线程的最大数量。

所以,无论是BIO,还是NIO,当请求数量大于acceptCount,接收的连接数大于maxConnection时,Tomcat都不会分配线程服务。

总结

一个请求过来,系统从线程池中分配一个可用的线程来处理当前请求的逻辑。

即某一请求的生命周期时间内,一个线程只用来处理一个请求,处理完之后,还给线程池(【特别注意】该线程还在,没被销毁,等待分配给别的页面请求用)

 

 

参考:https://www.zhihu.com/question/502043167/answer/2245846786