首页 > 编程语言 >学习分享-Tomcat 的线程池在工作方式上与普通的 Java 线程池的区别

学习分享-Tomcat 的线程池在工作方式上与普通的 Java 线程池的区别

时间:2024-06-12 16:30:40浏览次数:29  
标签:maxThreads Java 请求 Tomcat 队列 创建 线程

前言

最近在学习过程中遇到在某个场景下:修改某条数据时,给该线程上分布式写锁,然后引入延迟队列处理其他请求;这个方案有一定的缺点,因为在用到消息队列时,不存在占用过多线程从而导致OOM的问题,消费者组只会安排固定的几个线程去拉取消息,如果碰到上面那种拿不到锁的情况,阻塞等待就好。
上面这个场景设计到了Tomcat 的线程池,因此做一些分享。
Tomcat 的线程池在工作方式上有一些不同于普通的 Java 线程池 (如 ThreadPoolExecutor) 的地方,尤其是在处理线程的创建和任务的排队方面。

普通线程池(ThreadPoolExecutor)的工作方式

普通的 Java 线程池 (ThreadPoolExecutor) 按以下顺序处理任务:

  1. 核心线程:首先会创建和使用核心线程来处理任务,直到核心线程数达到 corePoolSize
  2. 阻塞队列:如果核心线程都在忙,并且有新的任务进来,任务会被放入阻塞队列(workQueue)中。
  3. 最大线程数:如果阻塞队列满了,并且还有新的任务,线程池会创建新的线程,直到线程总数达到 maximumPoolSize
  4. 拒绝策略:如果线程总数已经达到了 maximumPoolSize,并且阻塞队列也满了,新来的任务会根据拒绝策略(RejectedExecutionHandler)来处理。

Tomcat 线程池的工作方式

Tomcat 使用了一个自定义的线程池实现,它在处理请求时的行为与普通线程池有一些不同:

  1. 核心线程与最大线程:Tomcat 线程池中的 maxThreads 参数对应于普通线程池中的 maximumPoolSize,而 minSpareThreads 参数则与 corePoolSize 类似,但有一些不同。
  2. 直接创建新线程:Tomcat 在线程创建方面更加激进,当有新的请求进来时,如果所有当前线程都在忙,它会立即尝试创建新的线程,直到达到 maxThreads 数量。
  3. 任务队列:Tomcat 也有一个任务队列(acceptCount),但它的作用是当所有 maxThreads 都在忙时,用于排队等待处理的请求数量。如果这个队列也满了,新的请求会被拒绝或连接被关闭。
  4. 线程回收:Tomcat 会回收空闲的线程,保持至少 minSpareThreads 数量的线程处于空闲状态以便应对新的请求。

具体的区别

  • 线程创建时机

    • 普通线程池:先使用核心线程,然后任务进入队列,再创建额外线程。
    • Tomcat 线程池:在核心线程忙时,会直接创建新的线程直到 maxThreads
  • 队列的使用

    • 普通线程池:核心线程忙时,任务排队,队列满时才创建新的线程。
    • Tomcat 线程池:在所有线程都忙时,任务才进入队列。
  • 参数配置

    • 普通线程池:corePoolSize, maximumPoolSize, keepAliveTime, workQueue
    • Tomcat 线程池:maxThreads, minSpareThreads, acceptCount 等。

示例

普通线程池(ThreadPoolExecutor)示例
ExecutorService executorService = new ThreadPoolExecutor(
    10, // corePoolSize
    20, // maximumPoolSize
    60L, // keepAliveTime
    TimeUnit.SECONDS, // unit
    new LinkedBlockingQueue<Runnable>(100) // workQueue
);
Tomcat 线程池配置示例(在server.xml中)
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           maxThreads="200"
           minSpareThreads="25"
           acceptCount="100"
           maxConnections="5000"/>

在这个配置中:

  • maxThreads:最大线程数,表示 Tomcat 能够创建的最大工作线程数(类似于 maximumPoolSize)。
  • minSpareThreads:最小空闲线程数,即使没有请求,Tomcat 也会保持的空闲线程数。
  • acceptCount:最大排队请求数,当所有线程都在忙时,新的请求会进入这个队列。

总结

  • 普通线程池:主要通过核心线程处理任务,队列排队,最后才扩展到最大线程数。
  • Tomcat 线程池:更注重快速响应,会在核心线程忙时立即创建新线程,直到达到 maxThreads,只有在所有线程都忙时才使用队列来排队请求。

这种差异使得 Tomcat 在处理高并发 Web 请求时更加高效,因为它能够迅速扩展线程池以应对突然增加的请求负载,同时保持合理的空闲线程数来应对新请求。

标签:maxThreads,Java,请求,Tomcat,队列,创建,线程
From: https://blog.csdn.net/weixin_62079735/article/details/139603891

相关文章

  • SSM-小区物业管理系统-48954(免费领源码+开发文档)可做计算机毕业设计JAVA、PHP、爬虫、
    基于SSM小区物业管理系统摘要随着计算机科学技术日渐成熟,人们已经深刻认识到了计算机功能的强大,计算机已经进入到了人类社会发展的各个领域,并且发挥着十分重要的作用。每个社区的物业管理是一项系统而复杂的工作,它需要一个团队互相配合、分工协作。在该领域,传统的手工存取......
  • java 与jdk 关系
      java与jdk的关系Java与JDK的关系是,Java是一种编程语言,而JDK(JavaDevelopmentKit)是Java语言的官方开发工具包。12JDK是整个Java技术的核心,它包括了JRE(JavaRuntimeEnvironment)和一系列Java开发工具(如javac、java、javadoc等)。JRE是Jav......
  • 【问题解决】java.util.jar.JarException: file:bcprov-jdk18on-1.78.jar is not sign
    现象启动程序报错,同时在classpath下有多个bcprov-jdk开头的包Causedby:java.util.jar.JarException:file:/C:/Users/93986/.gradle/caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk18on/1.78/619aafb92dc0b4c6cc4cf86c487ca48ee2d67a8e/bcprov-jdk18on-1.78.jaris......
  • 网易面试:SpringBoot如何开启虚拟线程?
    虚拟线程(VirtualThread)也称协程或纤程,是一种轻量级的线程实现,与传统的线程以及操作系统级别的线程(也称为平台线程)相比,它的创建开销更小、资源利用率更高,是Java并发编程领域的一项重要创新。PS:虚拟线程正式发布于Java长期支持版(LongTermSuort,LTS)Java21(也就是JDK21)。......
  • JavaScript常用的流程控制语句
    在JavaScript中,有以下几种常用的流程控制语句:if...else:当if条件为假时,可以使用else语句执行另一段代码。if(condition){//条件为真时执行的代码}else{//条件为假时执行的代码}if...elseif...else:可以链式使用多个if和elseif来根据多个条件执行不......
  • 【S087】Springboot+Thymleaf在线答疑系统项目源码 java源代码
    运行截图:登录学生注册教师注册学生发起问题联系我们后台首页常见问题管理添加常见问题人工答疑学生管理个人信息修改密码项目组成:项目源码:源码获取⬇⬇⬇......
  • 【S086】基于Springboot图书馆管理系统项目源码 java图书借阅管理 含文档
    运行截图:登录后台主页图书列表图书上架借阅图书归还图书用户列表添加用户公告列表发布公告个人信息详情个人信息编辑项目组成:项目源码:项目文档:源码获取⬇⬇⬇......
  • Interlocked 为多个线程共享的变量提供原子操作 多线程重入
    Interlocked可以为多个线程共享的变量提供原子操作主要使用的读写方法varrunningState=Interlocked.Read(refisRunning);Interlocked.Exchange(refisRunning,0);可以配合lock实现业务常用方法Add(Int32,Int32) 对两个32位整数进行求和并用和替换第一个整数,上述操......
  • Java (WebDataBinder 枚举转换)
    前沿webDataBinder枚举类型转换 前端和后端数据请求的时候枚举类型 webDataBinder依赖于Converter实现类型转换,若Controller方法声明的@RequestParam参数的类型不是stringwebDataBinder就会自动进行数据类型转换。SpringMVC提供了常用类型的转换器,例如string到Integer、......
  • Java实际工作里用到的几种加密方式
    1、Base64加密最简单的加密方式,甚至可以说不是加密,只是一种用64个字符表示任意二进制数据的方法。Base64编码原理是将输入字符串按字节切分,取得每个字节对应的二进制值(若不足8比特则高位补0),然后将这些二进制数值串联起来,再按照6比特一组进行切分(因为2^6=64),最后一组若不足6比......