🧵 第四章:Tomcat 线程模型与运行方式
目录
- [4.1 线程模型概述](#4.1 线程模型概述)
- [4.2 支持的 I/O 模式](#4.2 支持的 I/O 模式)
- [4.3 线程生命周期管理](#4.3 线程生命周期管理)
- [4.4 运行模式详解](#4.4 运行模式详解)
- [4.5 性能对比分析](#4.5 性能对比分析)
- [4.6 配置优化建议](#4.6 配置优化建议)
- [4.7 本章小结](#4.7 本章小结)
4.1 线程模型概述
4.1.1 线程模型架构
整体架构图
业务处理 Worker 线程池 Poller 线程 Acceptor 线程 Servlet 处理 业务逻辑 数据库操作 Worker 1 Worker 2 Worker 3 Worker N Poller 1 Poller 2 Poller N Acceptor
线程职责分工
| 线程类型 | 职责 | 数量 | 生命周期 |
|---|---|---|---|
| Acceptor | 接受新连接 | 1个 | 长期运行 |
| Poller | 处理 I/O 事件 | 1-2个 | 长期运行 |
| Worker | 处理业务逻辑 | 可配置 | 按需创建 |
4.1.2 线程池配置
标准线程池
java
// 标准线程池实现
public class StandardThreadExecutor implements Executor {
private final ThreadPoolExecutor executor;
private final String name;
private final int maxThreads;
private final int minSpareThreads;
private final int maxSpareThreads;
private final long keepAliveTime;
public StandardThreadExecutor() {
this.maxThreads = 200;
this.minSpareThreads = 10;
this.maxSpareThreads = 50;
this.keepAliveTime = 60L;
// 创建线程池
this.executor = new ThreadPoolExecutor(
minSpareThreads, // 核心线程数
maxThreads, // 最大线程数
keepAliveTime, // 空闲时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(), // 工作队列
new ThreadFactory() { // 线程工厂
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix = "http-nio-8080-exec-";
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
);
}
@Override
public void execute(Runnable command) {
executor.execute(command);
}
}
自定义线程池
java
// 自定义线程池配置
public class CustomThreadExecutor implements Executor {
private final ThreadPoolExecutor executor;
public CustomThreadExecutor() {
// 核心线程数
int corePoolSize = 10;
// 最大线程数
int maximumPoolSize = 200;
// 空闲时间
long keepAliveTime = 60L;
// 时间单位
TimeUnit unit = TimeUnit.SECONDS;
// 工作队列
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);
// 线程工厂
ThreadFactory threadFactory = new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix = "custom-exec-";
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
};
// 拒绝策略
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
executor = new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue, threadFactory, handler);
}
}
4.2 支持的 I/O 模式
4.2.1 BIO(阻塞 I/O)
特点
- 阻塞模式:每个连接占用一个线程
- 简单实现:代码逻辑简单,易于理解
- 资源消耗:线程数量与连接数成正比
- 适用场景:连接数较少,并发量不高的应用
实现原理
java
// BIO 连接器实现
public class Http11Protocol extends AbstractHttp11Protocol<Socket> {
@Override
protected AbstractEndpoint.Handler<Socket> getHandler() {
return new Http11ConnectionHandler(this);
}
}
// BIO 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Socket, Http11Processor> {
@Override
protected Http11Processor createProcessor() {
Http11Processor processor = new Http11Processor(this);
processor.setAdapter(getAdapter());
return processor;
}
}
配置示例
xml
<!-- BIO 连接器配置 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="50"
acceptCount="100" />
4.2.2 NIO(非阻塞 I/O)
特点
- 非阻塞模式:使用事件驱动模型
- 高并发:少量线程处理大量连接
- 复杂实现:需要处理事件循环和状态管理
- 适用场景:高并发、长连接的应用
实现原理
java
// NIO 连接器实现
public class Http11NioProtocol extends AbstractHttp11Protocol<NioChannel> {
@Override
protected AbstractEndpoint.Handler<NioChannel> getHandler() {
return new Http11ConnectionHandler(this);
}
}
// NIO 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<NioChannel, Http11NioProcessor> {
@Override
protected Http11NioProcessor createProcessor() {
Http11NioProcessor processor = new Http11NioProcessor(this);
processor.setAdapter(getAdapter());
return processor;
}
}
事件循环
java
// NIO 事件循环
public class Poller implements Runnable {
private final Selector selector;
private final AtomicBoolean running = new AtomicBoolean(true);
@Override
public void run() {
while (running.get()) {
try {
// 等待事件
int keyCount = selector.select(selectorTimeout);
if (keyCount > 0) {
// 处理就绪的通道
Iterator<SelectionKey> iterator =
selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
// 处理 I/O 事件
processKey(key);
}
}
} catch (Exception e) {
// 处理异常
}
}
}
private void processKey(SelectionKey key) {
if (key.isReadable()) {
// 处理读事件
processRead(key);
} else if (key.isWritable()) {
// 处理写事件
processWrite(key);
}
}
}
配置示例
xml
<!-- NIO 连接器配置 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="50"
acceptCount="100"
maxConnections="8192" />
4.2.3 NIO2(AIO - 异步 I/O)
特点
- 异步模式:真正的异步 I/O 操作
- 回调机制:使用 CompletionHandler 处理结果
- 系统支持:需要操作系统支持异步 I/O
- 适用场景:高并发、异步处理的应用
实现原理
java
// NIO2 连接器实现
public class Http11Nio2Protocol extends AbstractHttp11Protocol<Nio2Channel> {
@Override
protected AbstractEndpoint.Handler<Nio2Channel> getHandler() {
return new Http11ConnectionHandler(this);
}
}
// NIO2 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Nio2Channel, Http11Nio2Processor> {
@Override
protected Http11Nio2Processor createProcessor() {
Http11Nio2Processor processor = new Http11Nio2Processor(this);
processor.setAdapter(getAdapter());
return processor;
}
}
异步处理
java
// 异步 I/O 处理
public class Http11Nio2Processor extends AbstractProcessorLight {
@Override
public SocketState service(SocketWrapperBase<Nio2Channel> socketWrapper)
throws IOException {
// 异步读取
socketWrapper.getSocket().read(
inputBuffer,
inputBuffer.position(),
inputBuffer.remaining(),
new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
// 处理读取结果
processRead(result);
}
@Override
public void failed(Throwable exc, Void attachment) {
// 处理读取失败
processError(exc);
}
}
);
return SocketState.OPEN;
}
}
配置示例
xml
<!-- NIO2 连接器配置 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="50"
acceptCount="100" />
4.2.4 APR(Apache Portable Runtime)
特点
- 原生实现:使用 C 语言实现,性能更高
- 系统优化:利用操作系统特性
- 依赖库:需要安装 APR 库
- 适用场景:对性能要求极高的应用
实现原理
java
// APR 连接器实现
public class Http11AprProtocol extends AbstractHttp11Protocol<Long> {
@Override
protected AbstractEndpoint.Handler<Long> getHandler() {
return new Http11ConnectionHandler(this);
}
}
// APR 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Long, Http11AprProcessor> {
@Override
protected Http11AprProcessor createProcessor() {
Http11AprProcessor processor = new Http11AprProcessor(this);
processor.setAdapter(getAdapter());
return processor;
}
}
配置示例
xml
<!-- APR 连接器配置 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="50"
acceptCount="100" />
4.3 线程生命周期管理
4.3.1 线程创建
线程工厂
java
// 自定义线程工厂
public class TomcatThreadFactory implements ThreadFactory {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
private final ThreadGroup group;
private final boolean daemon;
private final int priority;
public TomcatThreadFactory(String namePrefix) {
this(namePrefix, false, Thread.NORM_PRIORITY);
}
public TomcatThreadFactory(String namePrefix, boolean daemon, int priority) {
this.namePrefix = namePrefix;
this.daemon = daemon;
this.priority = priority;
this.group = Thread.currentThread().getThreadGroup();
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(daemon);
t.setPriority(priority);
return t;
}
}
线程创建流程
java
// 线程创建流程
public class StandardThreadExecutor implements Executor {
@Override
public void execute(Runnable command) {
// 1. 检查线程池状态
if (executor.isShutdown()) {
return;
}
// 2. 提交任务
executor.execute(command);
}
private void createWorkerThread(Runnable command) {
// 1. 创建线程
Thread worker = threadFactory.newThread(command);
// 2. 设置线程属性
worker.setDaemon(false);
worker.setPriority(Thread.NORM_PRIORITY);
// 3. 启动线程
worker.start();
}
}
4.3.2 线程调度
任务调度
java
// 任务调度器
public class TaskScheduler {
private final ScheduledExecutorService scheduler;
private final Map<String, ScheduledFuture<?>> tasks;
public TaskScheduler() {
this.scheduler = Executors.newScheduledThreadPool(1);
this.tasks = new ConcurrentHashMap<>();
}
public void scheduleTask(String name, Runnable task, long delay, TimeUnit unit) {
ScheduledFuture<?> future = scheduler.schedule(task, delay, unit);
tasks.put(name, future);
}
public void scheduleAtFixedRate(String name, Runnable task,
long initialDelay, long period, TimeUnit unit) {
ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(
task, initialDelay, period, unit);
tasks.put(name, future);
}
public void cancelTask(String name) {
ScheduledFuture<?> future = tasks.remove(name);
if (future != null) {
future.cancel(false);
}
}
}
线程池监控
java
// 线程池监控
public class ThreadPoolMonitor {
private final ThreadPoolExecutor executor;
private final ScheduledExecutorService monitor;
public ThreadPoolMonitor(ThreadPoolExecutor executor) {
this.executor = executor;
this.monitor = Executors.newScheduledThreadPool(1);
// 启动监控
startMonitoring();
}
private void startMonitoring() {
monitor.scheduleAtFixedRate(() -> {
// 监控线程池状态
int activeCount = executor.getActiveCount();
int poolSize = executor.getPoolSize();
int corePoolSize = executor.getCorePoolSize();
int maximumPoolSize = executor.getMaximumPoolSize();
long completedTaskCount = executor.getCompletedTaskCount();
long taskCount = executor.getTaskCount();
// 记录监控信息
log.info("ThreadPool Status: active={}, pool={}, core={}, max={}, completed={}, total={}",
activeCount, poolSize, corePoolSize, maximumPoolSize, completedTaskCount, taskCount);
}, 0, 30, TimeUnit.SECONDS);
}
}
4.3.3 线程销毁
优雅关闭
java
// 优雅关闭
public class GracefulShutdown {
private final ThreadPoolExecutor executor;
private final long timeout;
private final TimeUnit unit;
public GracefulShutdown(ThreadPoolExecutor executor, long timeout, TimeUnit unit) {
this.executor = executor;
this.timeout = timeout;
this.unit = unit;
}
public void shutdown() {
// 1. 停止接受新任务
executor.shutdown();
try {
// 2. 等待现有任务完成
if (!executor.awaitTermination(timeout, unit)) {
// 3. 强制关闭
executor.shutdownNow();
// 4. 再次等待
if (!executor.awaitTermination(timeout, unit)) {
log.warn("Thread pool did not terminate gracefully");
}
}
} catch (InterruptedException e) {
// 5. 中断当前线程
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
资源清理
java
// 资源清理
public class ResourceCleanup {
private final List<AutoCloseable> resources;
public ResourceCleanup() {
this.resources = new ArrayList<>();
}
public void addResource(AutoCloseable resource) {
resources.add(resource);
}
public void cleanup() {
for (AutoCloseable resource : resources) {
try {
resource.close();
} catch (Exception e) {
log.error("Error closing resource", e);
}
}
resources.clear();
}
}
4.4 运行模式详解
4.4.1 独立运行模式
启动脚本
bash
#!/bin/bash
# startup.sh
# 设置环境变量
export CATALINA_HOME="/opt/tomcat"
export CATALINA_BASE="/opt/tomcat"
export JAVA_HOME="/opt/java"
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m"
# 启动 Tomcat
exec "$CATALINA_HOME/bin/catalina.sh" run
停止脚本
bash
#!/bin/bash
# shutdown.sh
# 设置环境变量
export CATALINA_HOME="/opt/tomcat"
export CATALINA_BASE="/opt/tomcat"
# 停止 Tomcat
exec "$CATALINA_HOME/bin/catalina.sh" stop
配置管理
xml
<!-- 独立运行配置 -->
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context path="/myapp" docBase="myapp" />
</Host>
</Engine>
</Service>
</Server>
4.4.2 内嵌运行模式
Spring Boot 集成
java
// Spring Boot 应用
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// 自定义 Tomcat 配置
@Configuration
public class TomcatConfig {
@Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
// 自定义配置
context.addParameter("app.config", "production");
}
};
}
}
内嵌配置
java
// 内嵌 Tomcat 配置
public class EmbeddedTomcatConfig {
public static void main(String[] args) throws Exception {
// 创建 Tomcat 实例
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
// 设置基础目录
tomcat.setBaseDir(".");
// 添加上下文
Context context = tomcat.addContext("/myapp", ".");
// 添加 Servlet
Tomcat.addServlet(context, "MyServlet", new MyServlet());
context.addServletMappingDecoded("/myservlet", "MyServlet");
// 启动 Tomcat
tomcat.start();
tomcat.getServer().await();
}
}
4.4.3 反向代理模式
Nginx 配置
nginx
# nginx.conf
upstream tomcat_backend {
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082 weight=1;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://tomcat_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ {
alias /var/www/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
负载均衡配置
java
// 负载均衡配置
public class LoadBalancerConfig {
private final List<Server> servers;
private final AtomicInteger currentIndex;
public LoadBalancerConfig(List<Server> servers) {
this.servers = servers;
this.currentIndex = new AtomicInteger(0);
}
public Server getNextServer() {
int index = currentIndex.getAndIncrement() % servers.size();
return servers.get(index);
}
}
4.5 性能对比分析
4.5.1 I/O 模式性能对比
性能测试结果
| I/O 模式 | 并发连接数 | 响应时间 | 吞吐量 | 内存使用 | CPU 使用 |
|---|---|---|---|---|---|
| BIO | 1000 | 50ms | 1000 req/s | 高 | 高 |
| NIO | 10000 | 30ms | 5000 req/s | 中 | 中 |
| NIO2 | 10000 | 25ms | 6000 req/s | 中 | 中 |
| APR | 10000 | 20ms | 8000 req/s | 低 | 低 |
性能分析
java
// 性能测试代码
public class PerformanceTest {
public void testBIO() {
// BIO 性能测试
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
// 发送请求
sendRequest();
}
long endTime = System.currentTimeMillis();
System.out.println("BIO Time: " + (endTime - startTime) + "ms");
}
public void testNIO() {
// NIO 性能测试
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
// 发送请求
sendRequest();
}
long endTime = System.currentTimeMillis();
System.out.println("NIO Time: " + (endTime - startTime) + "ms");
}
}
4.5.2 线程模型性能对比
线程数量对比
java
// 线程数量统计
public class ThreadCountMonitor {
public void monitorThreads() {
// 获取线程信息
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
int threadCount = threadBean.getThreadCount();
int peakThreadCount = threadBean.getPeakThreadCount();
long totalStartedThreadCount = threadBean.getTotalStartedThreadCount();
System.out.println("Thread Count: " + threadCount);
System.out.println("Peak Thread Count: " + peakThreadCount);
System.out.println("Total Started Thread Count: " + totalStartedThreadCount);
}
}
内存使用对比
java
// 内存使用监控
public class MemoryMonitor {
public void monitorMemory() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();
System.out.println("Heap Used: " + heapUsage.getUsed() / 1024 / 1024 + "MB");
System.out.println("Heap Max: " + heapUsage.getMax() / 1024 / 1024 + "MB");
System.out.println("Non-Heap Used: " + nonHeapUsage.getUsed() / 1024 / 1024 + "MB");
}
}
4.6 配置优化建议
4.6.1 线程池优化
核心参数配置
xml
<!-- 线程池优化配置 -->
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="50"
acceptCount="100"
connectionTimeout="20000"
keepAliveTimeout="60000"
maxKeepAliveRequests="100" />
参数说明
| 参数 | 说明 | 推荐值 | 调优建议 |
|---|---|---|---|
| maxThreads | 最大线程数 | 200-500 | 根据 CPU 核心数调整 |
| minSpareThreads | 最小空闲线程数 | 10-50 | 保证快速响应 |
| maxSpareThreads | 最大空闲线程数 | 50-100 | 避免资源浪费 |
| acceptCount | 等待队列长度 | 100-200 | 根据并发量调整 |
| connectionTimeout | 连接超时时间 | 20000ms | 根据网络环境调整 |
| keepAliveTimeout | 保持连接时间 | 60000ms | 根据应用特性调整 |
4.6.2 内存优化
JVM 参数配置
bash
# JVM 参数优化
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
参数说明
| 参数 | 说明 | 推荐值 | 调优建议 |
|---|---|---|---|
| -Xms | 初始堆大小 | 512m | 与 -Xmx 相同 |
| -Xmx | 最大堆大小 | 1024m-2048m | 根据应用需求调整 |
| -XX:PermSize | 永久代初始大小 | 128m | Java 8 之前使用 |
| -XX:MaxPermSize | 永久代最大大小 | 256m | Java 8 之前使用 |
| -XX:MetaspaceSize | 元空间初始大小 | 128m | Java 8 及以后使用 |
| -XX:MaxMetaspaceSize | 元空间最大大小 | 256m | Java 8 及以后使用 |
4.6.3 系统优化
系统参数配置
bash
# 系统参数优化
# 文件句柄数
ulimit -n 65536
# 网络参数
echo 'net.core.somaxconn = 65536' >> /etc/sysctl.conf
echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_max_syn_backlog = 65536' >> /etc/sysctl.conf
# 应用参数
sysctl -p
参数说明
| 参数 | 说明 | 推荐值 | 调优建议 |
|---|---|---|---|
| ulimit -n | 文件句柄数 | 65536 | 根据连接数调整 |
| somaxconn | 监听队列长度 | 65536 | 提高并发处理能力 |
| netdev_max_backlog | 网络设备队列长度 | 5000 | 提高网络处理能力 |
| tcp_max_syn_backlog | TCP 连接队列长度 | 65536 | 提高 TCP 处理能力 |
4.7 本章小结
关键要点
-
线程模型:
- Acceptor 线程:接受新连接
- Poller 线程:处理 I/O 事件
- Worker 线程:处理业务逻辑
-
I/O 模式:
- BIO:阻塞 I/O,简单但性能较低
- NIO:非阻塞 I/O,高并发处理
- NIO2:异步 I/O,真正的异步处理
- APR:原生实现,性能最高
-
运行模式:
- 独立运行:传统部署方式
- 内嵌运行:Spring Boot 集成
- 反向代理:Nginx + Tomcat 架构
-
性能优化:
- 合理配置线程池参数
- 优化 JVM 参数
- 调整系统参数
选择建议
- 开发环境:使用 NIO 模式,配置简单
- 测试环境:使用 NIO 模式,性能适中
- 生产环境:使用 APR 模式,性能最优
- 高并发场景:使用 NIO2 模式,异步处理
下一步学习
在下一章中,我们将深入探讨 Tomcat 的配置体系与部署机制,了解各种配置文件的用途和配置方法,以及如何实现自动化部署和运维管理。
相关资源: