Tomcat深入浅出
1、Tomcat的线程池
1.1、基本介绍
Tomcat 线程池是 Tomcat 服务器用于管理和分配线程的一种机制。在处理客户端请求时,Tomcat 会从线程池中获取线程来执行任务,而不是为每个请求都创建一个新的线程。这样可以有效减少线程创建和销毁的开销,提高服务器的性能和资源利用率。
1.2、主要组件
1.2.1、核心线程数(corePoolSize)
这是线程池中的基本线程数量。当有新的请求到来,并且当前线程数量小于核心线程数时,线程池会创建新的线程来处理请求。例如,如果核心线程数设置为 10,那么在最初的 10 个请求到来时,线程池会创建 10 个线程来分别处理这些请求。
在 Tomcat 的默认配置中,核心线程数是 10。
1.2.2、最大线程数(maximumPoolSize)
线程池允许的最大线程数量。当请求数量超过核心线程数,并且队列已满时,线程池会继续创建线程,直到线程数量达到最大线程数。例如,最大线程数设置为 50,在高并发情况下,线程数量可能会从核心线程数逐渐增加到最大线程数来应对大量请求。
Tomcat 线程池默认的最大线程数是200
。
1.2.3、队列(BlockingQueue)
队列主要用于存放等待线程池中的线程来处理的客户端请求。当线程池中的所有线程都在忙碌,且尚未达到最大线程数时,新到达的请求会先被放入队列中等待处理,这可以有效地平滑请求流量的高峰,避免因短时间内大量请求涌入而导致系统崩溃。一旦队列满了,并且线程池中的线程数量还未达到最大线程数,Tomcat 就会迅速创建新的线程来处理请求。或者如果线程池中的某个线程被释放了,该线程会从队列中获取等待处理的请求并进行处理。当线程数大于等于核心线程数时,正常情况下只有当队列已满时,才会创建新的线程来处理新请求,直到线程数量达到maximumPoolSize。
Tomcat 使用的默认请求队列是org.apache.tomcat.util.threads.TaskQueue
,这个队列的大小在默认情况下没有严格的限制,不过在实际应用中,会受到 JVM 内存大小等因素的限制。例如,假设 JVM 中除了请求队列外,还有其他组件占用了一定的内存,剩余内存只够再容纳 100 个请求对象大小的空间。当队列中的请求数量已经达到这个极限时,并且再加入新请求就可能导致内存溢出,这种情况下队列实际上已满。
1.2.4、线程存活时间(keepAliveTime)
当线程池中的线程数量超过核心线程数,并且在一段时间内没有任务需要处理时,这些多余的线程会在存活时间过后被销毁。例如,如果存活时间设置为 60 秒,那么当一个线程空闲了 60 秒后,且线程数量大于核心线程数,这个线程就会被销毁。
Tomcat 线程池默认的线程存活时间是60
秒。
1.3、线程工作流程
- 请求到达:当客户端请求到达 Tomcat 服务器时,首先会检查线程池中的线程状态。
- 分配线程:如果有空闲线程(线程数量小于等于核心线程数),则将请求分配给空闲线程进行处理;如果没有空闲线程,但线程数量小于最大线程数,并且队列已满,则创建新的线程来处理请求;如果线程数量达到最大线程数,并且队列已满,那么请求可能会被拒绝(根据拒绝策略)。
- 线程回收:在处理完请求后,线程会回到线程池等待下一个任务。如果线程空闲时间超过存活时间,并且线程数量超过核心线程数,那么该线程会被回收。
1.4、线程大小的影响
线程大小的影响对CPU的影响:
- 太大:当最大线程数较大时,在高并发场景下会有更多的线程同时运行。这可能会导致 CPU 使用率大幅上升,因为每个线程都需要占用一定的 CPU 时间片来执行任务。例如,在一个复杂的 Web 应用中,如果最大线程数设置为 500,并且同时有大量请求到来,500 个线程可能会频繁地争夺 CPU 资源,使得 CPU 处于高负载状态。如果 CPU 核心数较少,可能会出现线程频繁切换的情况,这会消耗额外的 CPU 资源用于上下文切换,从而降低系统的整体性能。
- 太小:反之,若最大线程数设置得较小,如只有 10,在高并发情况下可能无法充分利用 CPU 资源。因为 CPU 可能有足够的能力处理更多的线程,但由于线程数的限制,请求只能在队列中等待或者被拒绝,导致系统的吞吐量较低。
1.5、配置与优化
- 根据应用场景配置参数:
- 对于高并发的 Web 应用,如电商网站的促销活动期间,可以适当增大核心线程数和最大线程数,同时选择合适的队列类型和大小,以应对大量的请求。而对于低并发的应用,如企业内部的管理系统,可以设置较小的核心线程数和最大线程数,以避免资源浪费。
- 例如,在一个预估并发请求数在 100 - 200 之间的应用中,可以将核心线程数设置为 50,最大线程数设置为 200,队列大小设置为 100,这样在一般情况下,50 个核心线程可以处理大部分请求,当请求增多时,最多可以利用 200 个线程和 100 个队列位置来处理高峰流量。
- 监控与调整:
- 可以使用 Tomcat 自带的监控工具或者第三方监控工具(如 JMX)来监控线程池的使用情况,包括线程的数量、队列的长度、线程的状态等。根据监控结果,及时调整线程池的参数,以优化服务器的性能。例如,如果发现请求经常被拒绝,可能需要增大最大线程数或队列大小。
1.6、Tomcat 最大线程数和Java程序创建的线程的关系
事实上,Tomcat 服务器线程池和 Java 程序通过 thread 创建的线程可以理解为互相独立的。Tomcat 的最大线程数并不影响 Java 程序创建的线程,比如当 Tomcat 服务器线程池最大线程数设为 10 时,通过 Java 创建的线程也可以超过 10。
两者互相独立:
两者之间的联系:
- 它们都运行在同一个 JVM 进程中,共享系统的 CPU、内存等资源。如果 Java 程序通过
Thread
创建了大量的线程,占用了过多的系统资源,可能会导致 Web 服务器线程池的线程获取资源不足,从而影响 Web 请求的处理性能。例如,当大量的自定义线程进行密集的 CPU 计算时,Web 服务器线程可能会因为 CPU 资源不足而处理请求变慢。