Tomcat 线程模型与请求处理(Executor + Worker 线程池)
在本篇文章中,我们完整解析了Tomcat 的线程模型与请求处理三种模型:BIO(阻塞)、NIO(非阻塞)、AIO(异步 IO)请求链路Executor 线程池:高效复用线程,避免资源耗尽核心源码配置优化:合理设置maxThreads👉 到这里,我们已经理解了Tomcat 如何利用线程池支撑高并发请求处理。
·
Tomcat 线程模型与请求处理(Executor + Worker 线程池)
1. 引言
在前几篇文章中,我们已经解析了 Connector 接收请求、Container 容器路由、Servlet 执行流程。
但要支撑 高并发请求处理,Tomcat 不能只依靠单线程:
- 一个请求需要绑定到一个线程处理
- 线程过多会导致系统崩溃(线程切换开销)
- 必须引入 线程池(Executor) 来复用线程
因此,本篇我们深入剖析 Tomcat 的线程模型与请求处理机制。
2. Tomcat 的线程模型演进
(1) 传统 BIO(阻塞 I/O)
- 每个请求一个线程
- 若请求等待时间长(如网络慢、IO阻塞),会大量占用线程
- 适合小规模并发
Socket → 一个请求一个线程
(2) NIO(非阻塞 I/O)
- 使用
Selector
统一管理 Socket - 请求就绪时分配线程处理
- 大幅减少线程占用
Socket → Selector → 可读/可写 → 线程池处理
(3) NIO.2 (AIO)
- 基于操作系统的异步 IO
- 请求到达时直接触发回调
- Tomcat 虽支持,但在高并发下实际效果不一定优于 NIO
3. Tomcat 中的 Executor(线程池)
Tomcat 使用 Executor(线程池) 管理 Worker 线程。
配置示例(server.xml
):
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="200" minSpareThreads="25"/>
Connector 引用 Executor:
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
executor="tomcatThreadPool"/>
4. 请求处理流程
请求处理的完整链路:
1. Acceptor 线程:接收 Socket 连接
2. Poller 线程:监听 Socket 是否可读(NIO Selector)
3. Worker 线程:从线程池取出线程,执行请求处理
👉 流程图:
Socket → Acceptor → Poller → Executor(Worker) → Container → Servlet
5. 核心源码解析
(1) Acceptor 接收请求
protected class Acceptor extends AbstractEndpoint.Acceptor {
@Override
public void run() {
while (running) {
SocketChannel socket = serverSock.accept();
if (socket != null) {
// 交给 Poller 注册到 Selector
poller.register(socket);
}
}
}
}
(2) Poller 监听事件
protected class Poller implements Runnable {
@Override
public void run() {
while (true) {
int keyCount = selector.select();
if (keyCount > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
// 交给 Worker 线程处理
processKey(key);
}
}
}
}
}
(3) Worker 线程执行
protected class Worker implements Runnable {
SocketWrapperBase<?> socket;
@Override
public void run() {
// 请求封装为 Request/Response
Http11Processor processor = new Http11Processor();
processor.process(socket);
}
}
(4) Processor 处理请求
public class Http11Processor {
public SocketState process(SocketWrapperBase<?> socket) {
// 解析 HTTP 请求行、头部、Body
prepareRequest(socket);
// 交给容器处理
adapter.service(request, response);
return SocketState.CLOSED;
}
}
6. 线程池调度策略
Tomcat 的 Executor
底层是 线程池实现(ThreadPoolExecutor),关键参数:
- maxThreads:最大线程数(并发上限)
- minSpareThreads:最小空闲线程数
- maxIdleTime:线程空闲存活时间
- queueSize:请求排队队列大小
运行时调度逻辑:
- 有空闲线程 → 直接分配
- 没有空闲线程 → 放入队列
- 队列满了 → 若没到
maxThreads
,则创建新线程 - 超过
maxThreads
→ 拒绝请求
7. 配置优化建议
(1) Executor 线程池
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="50" maxIdleTime="60000"/>
(2) Connector 配置
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
executor="tomcatThreadPool"
acceptCount="100"
connectionTimeout="20000"/>
参数解释:
- acceptCount:等待队列大小,超过则拒绝连接
- connectionTimeout:请求超时时间
8. 总结
在本篇文章中,我们完整解析了 Tomcat 的线程模型与请求处理:
- 三种模型:BIO(阻塞)、NIO(非阻塞)、AIO(异步 IO)
- 请求链路:Acceptor → Poller → Executor(Worker)
- Executor 线程池:高效复用线程,避免资源耗尽
- 核心源码:Acceptor、Poller、Worker、Http11Processor
- 配置优化:合理设置
maxThreads
、acceptCount
、connectionTimeout
👉 到这里,我们已经理解了 Tomcat 如何利用线程池支撑高并发请求处理。
更多推荐
所有评论(0)