Tomcat线程池详解,为什么SpringBoot最大支持200并发?

news/2024/10/22 8:00:56

Q:经典面试题,SpringBoot 应用可以同时并发处理多少请求?

A:SpringBoot 应用并发处理请求数主要由两个因素影响,使用的 Servlet容器(默认使用 Tomcat,常用的还有 jetty、undertow) 和 配置项。所以在默认配置下,SprigBoot 应用可以并发处理 200 请求。

那么这个200是怎么来的呢?SprigBoot 默认使用Tomcat,而Tomcat线程池的最大线程数就是200。到这里有朋友就有疑问了,并发数不是应该先受队列长度影响吗,难道队列长度也只有200,才会使用最大线程数吗?

Tomcat线程池

JDK 的线程池,是先使用核心线程数配置,接着使用队列长度,最后再使用最大线程配置。

Tomcat 的线程池,就是先使用核心线程数配置,再使用最大线程配置,最后才使用队列长度。

底层源码

runWorker

进入 runWorker 之后,这部分代码看起来很眼熟:

org.apache.Tomcat.util.threads.ThreadPoolExecutor.Worker#run

在 getTask 方法里面,可以看到关于线程池的几个关键参数:

org.apache.Tomcat.util.threads.ThreadPoolExecutor#getTask

  • corePoolSize,核心线程数,值为 10。

  • maximumPoolSize,最大线程数,值为 200。

而且基于 maximumPoolSize 这个参数,往前翻代码,会发现这个默认值就是 200:

Tomcat线程池默认队列长度:

Tomcat线程池:

  • 核心线程数,值为 10。

  • 最大线程数,值为 200。

  • 队列长度,值为 Integer.MAX_VALUE。

往线程池里面提交任务的时候,会执行 execute 这个方法:

org.apache.Tomcat.util.threads.ThreadPoolExecutor#execute(java.lang.Runnable)

对于 Tomcat 它会调用到 executeInternal 这个方法:

org.apache.Tomcat.util.threads.ThreadPoolExecutor#executeInternal

这个方法里面,标号为

  • ① 的地方,就是判断当前工作线程数是否小于核心线程数,小于则直接调用 addWorker 方法,创建线程。

  • ② 的地方主要是调用了 offer 方法,看看队列里面是否还能继续添加任务。

  • 如果不能继续添加,说明队列满了,则来到标号为 ③ 的地方,看看是否能执行 addWorker 方法,创建非核心线程,即启用最大线程数。

接下来看 workQueue.offer(command) 这个逻辑。如果返回 true 则表示加入到队列,返回 false 则表示启用最大线程数嘛。

workQueue.offer

这个 workQueue 是 TaskQueue,是 Tomcat 自己基于 LinkedBlockingQueue 搞的一个队列。

org.apache.Tomcat.util.threads.TaskQueue#offer

标号为 ① 的地方,判断了 parent 是否为 null,如果是则直接调用父类的 offer 方法。说明要启用这个逻辑,我们的 parent 不能为 null。

parent 就是 Tomcat 线程池,通过其 set 方法可以知道,是在线程池完成初始化之后,进行了赋值。也就是说,在 Tomcat 的场景下,parent 不会为空。

标号为 ② 的地方,调用了 getPoolSizeNoLock 方法:这个方法是获取当前线程池中有多个线程。所以如果这个表达式为 true:

parent.getPoolSizeNoLock() == parent.getMaximumPoolSize()

就表明当前线程池的线程数已经是配置的最大线程数了,那就调用 offer 方法,把当前请求放到到队列里面去。

标号为 ③ 的地方,是判断已经提交到线程池里面待执行或者正在执行的任务个数,是否比当前线程池的线程数还少。如果是,则说明当前线程池有空闲线程可以执行任务,则把任务放到队列里面去,就会被空闲线程给取走执行。

标号为 ④ 的地方。如果当前线程池的线程数比线程池配置的最大线程数还少,则返回 false。offer 方法返回 false,会出现什么情况?

offer返回false 则开始到上图中标号为 ③ 的地方,去尝试添加非核心线程了,也就是启用最大线程数这个配置了。

总结

JDK 的线程池,是先使用核心线程数配置,接着使用队列长度,最后再使用最大线程配置。

Tomcat 的线程池,就是先使用核心线程数配置,再使用最大线程配置,最后才使用队列长度。

那么如何调整增大SpringBoot的最大线程数呢?看到这里应该已经明白了,可以通过调整 最大线程数来 控制并发数量

面试题专栏

Java面试题专栏已上线,欢迎访问。

  • 如果你不知道简历怎么写,简历项目不知道怎么包装;
  • 如果简历中有些内容你不知道该不该写上去;
  • 如果有些综合性问题你不知道怎么答;

那么可以私信我,我会尽我所能帮助你。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/74479.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Apache Pig 系列 一 [PIG的安装]

1 - 系统环境2- 下载PIGwget https://github.com/apache/pig/archive/refs/tags/release-0.17.0.tar.gz 3- 解压tar -zxvf release-0.17.0.tar.gz 4-构建 构建报错, 使用其他的方式下载wget https://mirrors.tuna.tsinghua.edu.cn/apache/pig/pig-0.17.0/pig-0.17.0.tar.gz …

帝国cms伪静态设置方法

众所周知,动态页面不利于收录和排名。伪静态可以完美的解决这问题,配合百度云加速等免费CDN,可以让动态页面有静态页面一样快的访问速度。今天我给大家带来帝国CMS伪静态的详细设置方法。 1.栏目设置为动态访问修改单个栏目属性,如下图批量修改栏目属性,如下图:2.首页也设…

Termux使用的一些细节

开启ssh pkg i openssh # 启动ssh服务 sshd # 设置密码 passwd # 查看本机ip,找到wlan0或者直接找192开头的ip ifconfig默认的端口是8022。 有不少教程是写一个whoami命令,但是我实测直接使用root作为用户名即可(和root权限无关)以下是ssh配置的路径,有端口号等信息/data/…

[Linux Mint]安装搜狗输入法

造冰箱的大熊猫@cnblogs 2024/10/22, Linux Mint 1、从官网下载搜狗拼音输入法的deb包2、安装deb包sudo apt deb sogoupinyin.deb 3、设置输入法框架 - 启动Input Method,将“Input method framework”设置为fcitx - 选择“Simplified Chinese”,点击“Install the language…

chapter4

通过python process.run.py -h命令了解了process.run.py的可用的选项 题外话(关于/home目录的): /home 目录是 Linux 系统中用于存储用户个人文件的地方。每个用户在 /home 下都有一个以其用户名命名的子目录,用于存放该用户的个人数据和设置。以下是一些 /home 目录的特点…

如何以最简单的方式传输文件到开发板上-lrzsz-ZModem

在某鱼上闲逛的时候,看到树莓派A+这个型号的板子,很便宜30来块钱,有6ULL的性能。 但是既没有网口、也没有WiFi,只有一个usb,电脑和它传数据岂不是非常麻烦?其实有一个非常好用的协议叫ZModem,它的设计就是主要为了能在串口这种几乎无需配置的连接协议上传输文件。类似的…

东山Pi柒号-3-STM32MP1 引导链概述

进行移植前先看看ST官网的一些资料,了解芯片的工作方式: STM32MP1 引导链概述 https://wiki.stmicroelectronics.cn/stm32mpu/wiki/STM32MP1_boot_chain_overview启动步骤如下BROM(BL1):芯片内部程序,根据BOOT PIN读取对应启动设备里的程序到内部SYSRAM执行,工作在在Secur…

派生类

派生类 1. 派生类2. 派生类对象定义时调用构造函数的顺序 Man man;3. public、protected、private 4. 函数遮蔽