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

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

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

Tomcat线程池

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

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

底层源码

runWorker

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

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

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

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

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

Tomcat线程池默认队列长度:

Tomcat线程池:

  • 核心线程数,值为 10。

  • 最大线程数,值为 200。

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

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

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

这个方法里面,标号为

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

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

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

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

workQueue.offer

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

标号为 ① 的地方,判断了 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面试题专栏已上线,欢迎访问。

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

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

Tomcat线程池详解,为什么SpringBoot最大支持200并发?的更多相关文章

  1. Java线程池详解(二)

    一.前言 在总结了线程池的一些原理及实现细节之后,产出了一篇文章:Java线程池详解(一),后面的(一)是在本文出现之后加上的,而本文就成了(二).因为在写完第一篇关于java线程池的文章之后,越发觉 ...

  2. nginx源码分析线程池详解

    nginx源码分析线程池详解 一.前言     nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...

  3. 三、VIP课程:并发编程专题->01-并发编程之Executor线程池详解

    01-并发编程之Executor线程池详解 线程:什么是线程&多线程 线程:线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系 ...

  4. Tomcat 连接数与线程池详解

    前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xm ...

  5. Java 并发编程 | 线程池详解

    原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...

  6. java - jdk线程池详解

    线程池参数详解 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUni ...

  7. Tomcat 连接池详解

    (转) JDBC 连接池 org.apache.tomcat.jdbc.pool 是Apache-Commons DBCP连接池的一种替换或备选方案. 那究竟为何需要一个新的连接池? 原因如下: Co ...

  8. java/android线程池详解

    一,简述线程池: 线程池是如何工作的:一系列任务出现后,根据自己的线程池安排任务进行. 如图: 线程池的好处: 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销. 能有效控制线程池的最大并 ...

  9. Java线程池详解

    一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多 ...

  10. Java多线程之线程池详解

    前言 在认识线程池之前,我们需要使用线程就去创建一个线程,但是我们会发现有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因 ...

随机推荐

  1. 基于浅层神经网络(全连接网络)的强化学习算法(Reinforce) 在训练过程中出现梯度衰退(degenerate)的现象

    首先给出一个代码地址: https://gitee.com/devilmaycry812839668/CartPole-PolicyNetwork 强化学习中的策略网络算法.<TensorFlo ...

  2. pytorch不像TensorFlow那样有专用的文件存储格式真的是不足吗?pytorch该如何处理大量小文件的读取呢?

    偶然发现前文: [转载] PyTorch下训练数据小文件转大文件读写(附有各种存储格式对比) 在谈论pytorch的文件读取问题,因为以前是搞TensorFlow的,后来由于编写效率和生态环境问题转为 ...

  3. 从源码分析 SpringBoot 的 LoggingSystem → 它是如何绑定日志组件的

    开心一刻 今天心情不好,想约哥们喝点 我:心情不好,给你女朋友说一声,来我家,过来喝点 哥们:行!我给她说一声 我:你想吃啥?我点外卖 哥们:你俩定吧,我已经让她过去了 我:???我踏马让你过来!和她 ...

  4. WIN32下的模拟时钟

    #include <Windows.h> #include <math.h> #include <tchar.h> #include "resource. ...

  5. 记一个文件过大导致git失败的修复方法

    原因: 测试文件流时候弄了个安装包进去,结果太大了 解决方法: 参考蓝色行,先取到故障的文件名 然后 git filter-branch --tree-filter 'rm -f 文件名' --tag ...

  6. Ubuntu 添加虚拟内存文件

    添加交换文件 准备工作 查看当前系统中启用的交换空间(swap space)的详细信息: sudo swapon --show 查看系统的内存和总交换空间的使用情况: free -h 为了有足够的空间 ...

  7. Homebrew 卸载 Wireshark 报错

    我在使用 Homebrew 安装 Wireshark 的时候,Homebrew 要求我输入密码.此时我又不想安转 Wireshark 了,于是我没有输入密码并且按下了 Ctrl + C.后来,我又尝试 ...

  8. Android RecyclerView 获取当前滚动到的Item项

    背景:RecyclerView  左右滑动时,需要获取当前显示在页面上的选项卡 步骤: 1. RecyclerView  添加addOnScrollListener,回调中可以直接获取对应Item I ...

  9. Java 多个String(字符串)判断是否null(空值)

    Java 多个String(字符串)判断是否null(空值) 示例: String s = null; if (str1 != null) { s = str1; } else if (str2 != ...

  10. C++: 智能指针的自定义删除器 `Custom Deleter` 有什么用?

    C++11智能指针std::shared_ptr和std::unique_ptr都支持自定义删除器,本文将介绍自定义删除器的使用场景和使用方法.智能指针模板参数的第二个类型是删除器,一般是一个函数指针 ...