第四章-Tomcat线程模型与运行方式 - 指南

第四章:Tomcat 线程模型与运行方式

目录


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 线程池配置

标准线程池
// 标准线程池实现
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);
  }
  }
自定义线程池
// 自定义线程池配置
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)

特点
  • 阻塞模式:每个连接占用一个线程
  • 简单实现:代码逻辑简单,易于理解
  • 资源消耗:线程数量与连接数成正比
  • 适用场景:连接数较少,并发量不高的应用
实现原理
// 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;
      }
      }
配置示例
<!-- 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> {
  @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;
      }
      }
事件循环
// 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);
  }
  }
  }
配置示例
<!-- 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> {
  @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;
      }
      }
异步处理
// 异步 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;
    }
    }
配置示例
<!-- 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> {
  @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;
      }
      }
配置示例
<!-- 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();
}
@Override
public 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 {
@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 线程调度

任务调度
// 任务调度器
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 {
@Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
@Override
protected 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", ".");
// 添加 Servlet
Tomcat.addServlet(context, "MyServlet", new MyServlet());
context.addServletMappingDecoded("/myservlet", "MyServlet");
// 启动 Tomcat
tomcat.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 使用
BIO100050ms1000 req/s
NIO1000030ms5000 req/s
NIO21000025ms6000 req/s
APR1000020ms8000 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永久代初始大小128mJava 8 之前使用
-XX:MaxPermSize永久代最大大小256mJava 8 之前使用
-XX:MetaspaceSize元空间初始大小128mJava 8 及以后使用
-XX:MaxMetaspaceSize元空间最大大小256mJava 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_backlogTCP 连接队列长度65536提高 TCP 处理能力

4.7 本章小结

关键要点

  1. 线程模型

    • Acceptor 线程:接受新连接
    • Poller 线程:处理 I/O 事件
    • Worker 线程:处理业务逻辑
  2. I/O 模式

    • BIO:阻塞 I/O,简单但性能较低
    • NIO:非阻塞 I/O,高并发处理
    • NIO2:异步 I/O,真正的异步处理
    • APR:原生实现,性能最高
  3. 运行模式

    • 独立运行:传统部署方式
    • 内嵌运行:Spring Boot 集成
    • 反向代理:Nginx + Tomcat 架构
  4. 性能优化

    • 合理配置线程池参数
    • 优化 JVM 参数
    • 调整系统参数

选择建议

  1. 开发环境:使用 NIO 模式,配置简单
  2. 测试环境:使用 NIO 模式,性能适中
  3. 生产环境:使用 APR 模式,性能最优
  4. 高并发场景:使用 NIO2 模式,异步处理

下一步学习

在下一章中,我们将深入探讨 Tomcat 的配置体系与部署机制,了解各种配置文件的用途和配置方法,以及如何实现自动化部署和运维管理。


相关资源

posted @ 2025-11-23 21:19  yangykaifa  阅读(2)  评论(0)    收藏  举报