第四章-Tomcat线程模型与运行方式
🧵 第四章:Tomcat 线程模型与运行方式
目录
- 4.1 线程模型概述
- 4.2 支持的 I/O 模式
- 4.3 线程生命周期管理
- 4.4 运行模式详解
- 4.5 性能对比分析
- 4.6 配置优化建议
- 4.7 本章小结
4.1 线程模型概述
4.1.1 线程模型架构
整体架构图
线程职责分工
| 线程类型 | 职责 | 数量 | 生命周期 |
|---|---|---|---|
| Acceptor | 接受新连接 | 1个 | 长期运行 |
| Poller | 处理 I/O 事件 | 1-2个 | 长期运行 |
| Worker | 处理业务逻辑 | 可配置 | 按需创建 |
4.1.2 线程池配置
标准线程池
// 标准线程池实现
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-";@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());t.setDaemon(false);t.setPriority(Thread.NORM_PRIORITY);return t;}});}@Overridepublic void execute(Runnable command) {executor.execute(command);}
}
自定义线程池
// 自定义线程池配置
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-";@Overridepublic 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)
特点
- 阻塞模式:每个连接占用一个线程
- 简单实现:代码逻辑简单,易于理解
- 资源消耗:线程数量与连接数成正比
- 适用场景:连接数较少,并发量不高的应用
实现原理
// BIO 连接器实现
public class Http11Protocol extends AbstractHttp11Protocol<Socket> {@Overrideprotected AbstractEndpoint.Handler<Socket> getHandler() {return new Http11ConnectionHandler(this);}
}// BIO 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Socket, Http11Processor> {@Overrideprotected Http11Processor createProcessor() {Http11Processor processor = new Http11Processor(this);processor.setAdapter(getAdapter());return processor;}
}
配置示例
<!-- BIO 连接器配置 -->
<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"maxThreads="200"minSpareThreads="10"maxSpareThreads="50"acceptCount="100" />
4.2.2 NIO(非阻塞 I/O)
特点
- 非阻塞模式:使用事件驱动模型
- 高并发:少量线程处理大量连接
- 复杂实现:需要处理事件循环和状态管理
- 适用场景:高并发、长连接的应用
实现原理
// NIO 连接器实现
public class Http11NioProtocol extends AbstractHttp11Protocol<NioChannel> {@Overrideprotected AbstractEndpoint.Handler<NioChannel> getHandler() {return new Http11ConnectionHandler(this);}
}// NIO 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<NioChannel, Http11NioProcessor> {@Overrideprotected Http11NioProcessor createProcessor() {Http11NioProcessor processor = new Http11NioProcessor(this);processor.setAdapter(getAdapter());return processor;}
}
事件循环
// NIO 事件循环
public class Poller implements Runnable {private final Selector selector;private final AtomicBoolean running = new AtomicBoolean(true);@Overridepublic 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);}}
}
配置示例
<!-- 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
- 适用场景:高并发、异步处理的应用
实现原理
// NIO2 连接器实现
public class Http11Nio2Protocol extends AbstractHttp11Protocol<Nio2Channel> {@Overrideprotected AbstractEndpoint.Handler<Nio2Channel> getHandler() {return new Http11ConnectionHandler(this);}
}// NIO2 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Nio2Channel, Http11Nio2Processor> {@Overrideprotected Http11Nio2Processor createProcessor() {Http11Nio2Processor processor = new Http11Nio2Processor(this);processor.setAdapter(getAdapter());return processor;}
}
异步处理
// 异步 I/O 处理
public class Http11Nio2Processor extends AbstractProcessorLight {@Overridepublic SocketState service(SocketWrapperBase<Nio2Channel> socketWrapper) throws IOException {// 异步读取socketWrapper.getSocket().read(inputBuffer, inputBuffer.position(), inputBuffer.remaining(), new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer result, Void attachment) {// 处理读取结果processRead(result);}@Overridepublic void failed(Throwable exc, Void attachment) {// 处理读取失败processError(exc);}});return SocketState.OPEN;}
}
配置示例
<!-- 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 库
- 适用场景:对性能要求极高的应用
实现原理
// APR 连接器实现
public class Http11AprProtocol extends AbstractHttp11Protocol<Long> {@Overrideprotected AbstractEndpoint.Handler<Long> getHandler() {return new Http11ConnectionHandler(this);}
}// APR 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Long, Http11AprProcessor> {@Overrideprotected Http11AprProcessor createProcessor() {Http11AprProcessor processor = new Http11AprProcessor(this);processor.setAdapter(getAdapter());return processor;}
}
配置示例
<!-- 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 线程创建
线程工厂
// 自定义线程工厂
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();}@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());t.setDaemon(daemon);t.setPriority(priority);return t;}
}
线程创建流程
// 线程创建流程
public class StandardThreadExecutor implements Executor {@Overridepublic 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 线程调度
任务调度
// 任务调度器
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);}}
}
线程池监控
// 线程池监控
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 线程销毁
优雅关闭
// 优雅关闭
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();}}
}
资源清理
// 资源清理
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 独立运行模式
启动脚本
#!/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
停止脚本
#!/bin/bash
# shutdown.sh# 设置环境变量
export CATALINA_HOME="/opt/tomcat"
export CATALINA_BASE="/opt/tomcat"# 停止 Tomcat
exec "$CATALINA_HOME/bin/catalina.sh" stop
配置管理
<!-- 独立运行配置 -->
<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 集成
// Spring Boot 应用
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}// 自定义 Tomcat 配置
@Configuration
public class TomcatConfig {@Beanpublic TomcatServletWebServerFactory tomcatFactory() {return new TomcatServletWebServerFactory() {@Overrideprotected void postProcessContext(Context context) {// 自定义配置context.addParameter("app.config", "production");}};}
}
内嵌配置
// 内嵌 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", ".");// 添加 ServletTomcat.addServlet(context, "MyServlet", new MyServlet());context.addServletMappingDecoded("/myservlet", "MyServlet");// 启动 Tomcattomcat.start();tomcat.getServer().await();}
}
4.4.3 反向代理模式
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";}
}
负载均衡配置
// 负载均衡配置
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 | 低 | 低 |
性能分析
// 性能测试代码
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 线程模型性能对比
线程数量对比
// 线程数量统计
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);}
}
内存使用对比
// 内存使用监控
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 线程池优化
核心参数配置
<!-- 线程池优化配置 -->
<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 参数配置
# 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 系统优化
系统参数配置
# 系统参数优化
# 文件句柄数
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 的配置体系与部署机制,了解各种配置文件的用途和配置方法,以及如何实现自动化部署和运维管理。
相关资源:
- Tomcat 线程模型文档
- NIO 编程指南
- Spring Boot 内嵌 Tomcat
