StandardThreadExecutor源码解读与使用(tomcat的线程池实现类)

🏷️个人主页:牵着猫散步的鼠鼠 

🏷️系列专栏:Java源码解读-专栏

🏷️个人学习笔记,若有缺误,欢迎评论区指正 

目录

目录

1.前言

2.线程池基础知识回顾

2.1.线程池的组成

2.2.工作流程

2.3.Java 中的线程池实现

3.StandardThreadExecutor介绍

4.源码解读

5.使用场景

6.总结


1.前言

        这个系列已经鸽了三四个月啦,原本预期一周一更的速度,变成了一季度一更(悲),最近打算继续重拾这个专栏继续与大家分享自己的随笔,尽量做到一周一更或者一周两更,今天想和大家分享一个在工作遇到的线程池类StandardThreadExecutor。

2.线程池基础知识回顾

        首先我们来简单介绍下线程池的基础概念:

        在 Java 中,线程池是一种用于管理和复用线程的机制,能够有效提高应用程序的性能和资源利用率。线程池的核心思想是通过复用一组预先创建的线程来执行多个任务,从而减少线程创建和销毁的开销。

2.1.线程池的组成

  • 核心线程数:始终保持活跃的线程数量,即使它们处于空闲状态。
  • 最大线程数:线程池能够容纳的最大线程数量。
  • 任务队列:用于存储等待执行的任务。
  • 拒绝策略:当任务无法被执行时的处理策略。

2.2.工作流程

当有新任务提交时,如果当前线程数小于核心线程数,线程池会创建新线程执行任务。 如果核心线程都在忙,则任务被放入队列中。 当队列已满且线程数小于最大线程数时,线程池会创建新线程。 如果线程数已达到最大值且队列也满了,则根据拒绝策略处理任务。

2.3.Java 中的线程池实现

Java 提供了多种线程池实现,最常用的是 ThreadPoolExecutor,它允许我们根据需求配置线程池的各项参数。

此外,我们还可以通过 Executors 工具类创建线程池,Java 提供了几种常用的默认线程池:

  • FixedThreadPool:具有固定线程数的线程池,适用于负载较为稳定的场景。
  • CachedThreadPool:根据需要创建新线程的线程池,适用于执行大量短期异步任务。
  • ScheduledThreadPool:支持定时和周期性任务执行的线程池。
  • SingleThreadExecutor:单线程化的线程池,适用于需要顺序执行任务的场景。

3.StandardThreadExecutor介绍

        StandardThreadExecutor Apache Tomcat 中的一个线程池实现类,用于管理和调度线程的执行。它类似于 Java ThreadPoolExecutor

        既然JDK已经提供了如此多的选择,Tomcat为什么还有自己编写一个线程池实现类呢,下面就解答这个疑问

        StandardThreadExecutor Catalina 结构中的一部分,是 Tomcat 生命周期中的池化线程资源的封装。StandardThreadExecutor 是为了更好地适应 Tomcat 容器中 HTTP 请求的处理而设计的,它包含了一些特殊的优化和功能。

        他与官方线程池相比最大的区别为内部任务的执行逻辑,JDK默认的线程池的execute方法执行逻辑如下:

1.任务数小于等于核心线程数:使用核心线程执行;
2.任务数大于核心线程数:加入任务等待队列等待;
3.队列满且任务数小于最大线程数:有空闲线程使用空闲线程执行,没有的话,创建非核心线程执行;

4.任务数大于最大核线程数:执行拒绝策略

我们这里为了方便理解可以简单表达为:核心线程 -> 等待队列 ->非核心线程 ->拒绝策略

对这一块不太了解的,可以去看看博主之前的线程池文章,参照官方线程池思想编写的简易线程池,方便大家理解线程池的执行逻辑
Java手搓线程池_牵着猫散步的鼠鼠的博客-CSDN博客

而 StandardThreadExecutor其中的执行逻辑如下:

1.任务数小于等于核心线程数:使用核心线程执行;
2.任务数大于核心线程数:创建非核心线程执行;
3.任务数大于最大核线程数:加入任务等待队列等待;

4.任务数大于最大核线程数且等待队列满了:执行拒绝策略

我们这里为了方便理解简单表达为:核心线程 -> 非核心线程 -> 等待队列 -> 拒绝策略

        我们可以看到,StandardThreadExecutor的执行逻辑主要是将创建非核心线程执行这一步放到了加入等待队列等待前面,等待队列只是作为一个靠后的兜底处理,我们举一个具体的案例来说明。
        假如我们有如下线程池配置

         同一时间提交了20个任务,对于官方的线程池,最初的状态如下

        可以看到,由于我们等待队列的大小足够大,对于4个核心线程处理不完的16个核心线程会先加入到等待队列中等待,对于一些执行时间长的任务,长时间等待就会造成性能问题。

        而对于 StandardThreadExecutor 这个线程池实现类,最初的状态如下:

        可以看到, StandardThreadExecutor 对于核心线程执行不了的任务会直接创建非核心线程来执行,相比于官方线程池放入等待队列会有更高的执行效率,确保服务器在高负载下仍能保持良好的响应性能。

4.源码解读

        接下来我们继续深入 StandardThreadExecutor 类的源码了解其内部是如何实现的。

        StandardThreadExecutor 继承自 LifecycleMBeanBase,并实现了 Executor ResizableExecutor 接口 ,这意味着它不仅是一个线程池执行器,还可以与 Tomcat 的生命周期管理集成。

有如下关键属性: 

  • threadPriority:线程优先级,默认值为 5。
  • daemon:线程是否为守护线程,默认值为 true。 namePrefix:线程名称前缀,用于标识线程。
  • maxThreads 和 minSpareThreads:最大线程数和最小空闲线程数。
  • maxIdleTime:线程最大空闲时间。
  • maxQueueSize:任务队列的最大容量。
  • threadRenewalDelay:线程重生延迟时间。
  • taskqueue:任务队列,用于存储等待执行的任务。
  • executor:核心的 ThreadPoolExecutor 实例,负责管理线程的创建和任务的调度。

StandardThreadExecutor关键方法有三个,分别是

  • startInternal():启动线程池,初始化 TaskQueue 和 ThreadPoolExecutor。
  • stopInternal():停止线程池并清理资源
  • execute(Runnable command):提交任务给线程池执行。 如果线程池未启动,抛出异常。

其中 stopInternal() execute(Runnable command) 两个方法没有太多逻辑,我们主要关注 startInternal() 启动线程池这一步初始化操作,startInternal() 方法如下:

    @Overrideprotected void startInternal() throws LifecycleException {taskqueue = new TaskQueue(maxQueueSize);TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority());executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);executor.setThreadRenewalDelay(threadRenewalDelay);taskqueue.setParent(executor);setState(LifecycleState.STARTING);}

 startInternal() 主要是进行了 taskqueue 任务队列和 executor 线程池的初始化,我们接着查看 taskqueue 的实现

 TaskQueue 继承自 LinkedBlockingQueue<Runnable>,接着我们可以发现TaskQueue重写了offer方法

这里我们可以看到, TaskQueue 在调用父类 offer 方法前添加了许多条件判断,这里其实就是 StandardThreadExecutor 调整任务提交顺序的代码实现位置,

@Override
public boolean offer(Runnable o) {// 首先检查线程池的状态。if (parent==null) {return super.offer(o);}// 如果当前线程池中的线程数达到最大值,则直接将任务加入队列。if (parent.getPoolSizeNoLock() == parent.getMaximumPoolSize()) {return super.offer(o);}// 如果提交的任务数小于或等于当前线程池的线程数,则将任务加入队列。if (parent.getSubmittedCount() <= parent.getPoolSizeNoLock()) {return super.offer(o);}// 如果当前线程数小于最大线程数,则返回 false,促使 ThreadPoolExecutor 创建新线程。if (parent.getPoolSizeNoLock() < parent.getMaximumPoolSize()) {return false;}//if we reached here, we need to add it to the queuereturn super.offer(o);
}

        当前线程数小于最大线程数时,线程池实例调用 TaskQueue offer() 方法会返回 false,此时线程池会判定任务队列满了,就会去创建新线程来执行任务。

5.使用场景

在像 Tomcat 这样的应用服务器中,用于处理大量并发请求。StandardThreadExecutor 可以有效管理线程的创建和销毁,提升服务器的响应能力和资源利用效率。

此外,在一些高并发对响应速度要求较高的场景,StandardThreadExecutor 可以有效避免任务过多积压在队列中,提高任务的响应速度,但是要注意配置合理的核心线程数和最大线程数,尽量减少线程的频繁创建和销毁。

6.总结

        StandardThreadExecutor Apache Tomcat 中的一个线程池实现类,是 Tomcat 生命周期中的池化线程资源的封装。StandardThreadExecutor 是为了更好地适应 Tomcat 容器中 HTTP 请求的处理而设计的。通过优先创建非核心线程来执行任务,避免了任务在等待队列中长时间积压,从而提升了服务器的响应速度。

      StandardThreadExecutor 内部主要通过自定义 TaskQueue 任务队列,·继承普通任务队列冰重写 offer() 方法,添加了线程数小于最大线程数的判断,巧妙的调整了任务提交的顺序。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端埋点与监控最佳实践:从基础到全流程实现.

前端埋点与监控最佳实践&#xff1a;从基础到全流程实现 大纲 我们会从以下三个方向来讲解埋点与监控的知识&#xff1a; 什么是埋点&#xff1f;什么是监控&#xff1f; JS 中实现监控的核心方案 写一个“相对”完整的监控实例 一、什么是埋点&#xff1f;什么是监控&am…

rom定制系列------红米k30_4G版澎湃os安卓13批量线刷固件

&#x1f49d;&#x1f49d;&#x1f49d;红米k30 4G版&#xff0c;机型代码;phoenix.此机型官方固件最后一版为稳定版13.0.6安卓12的固件。客户的软件需运行在至少安卓13的系统至少。测试原生适配有bug。最终测试在第三方澎湃os安卓13的固件可以完美运行。 &#x1f49d;&am…

钉钉平台开发小程序

一、下载小程序开发者工具 官网地址&#xff1a;小程序开发工具 - 钉钉开放平台 客户端类型 下载链接 MacOS x64 https://ur.alipay.com/volans-demo_MiniProgramStudio-x64.dmg MacOS arm64 https://ur.alipay.com/volans-demo_MiniProgramStudio-arm64.dmg Windows ht…

android——渐变色

1、xml的方式实现渐变色 效果图&#xff1a; xml的代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools…

微信小程序生成二维码

目前是在开发小程序端 --> 微信小程序。然后接到需求&#xff1a;根据 form 表单填写内容生成二维码&#xff08;第一版&#xff1a;表单目前需要客户进行自己输入&#xff0c;然后点击生成按钮实时生成二维码&#xff0c;不需要向后端请求&#xff0c;不存如数据库&#xf…

rhce:web服务器

web服务器简介 服务器端&#xff1a;此处使用 nginx 提供 web 服务&#xff0c; RPM 包获取&#xff1a; http://nginx.org/packages/ /etc/nginx/ ├── conf.d #子配置文件目录 ├── default.d ├── fastcgi.conf ├── fastcgi.conf.default ├── fastcgi_params #用…

解决使用netstat查看端口显示FIN_WAIT的问题

解决使用netstat查看端口显示FIN_WAIT的问题 1. 理解`FIN_WAIT`状态2. 检查应用程序3. 检查网络延迟和稳定性4. 更新和修补系统5. 调整TCP参数6. 使用更详细的工具进行分析7. 咨询开发者或技术支持8. 定期监控和评估结论在使用 netstat查看网络连接状态时,如果发现大量连接处…

01LangChain 实战课开篇——AI奇点时刻

LangChain 实战课开篇——AI奇点时刻 课程简介 课程背景&#xff1a;随着ChatGPT和GPT-4的出现&#xff0c;AI技术与实际应用之间的距离变得前所未有的近。LangChain作为基于大模型的应用开发框架&#xff0c;为程序员提供了开发智能应用的新工具。 LangChain 概述 定义&am…

【java】java的基本程序设计结构06-运算符

运算符 一、分类 算术运算符关系运算符位运算符逻辑运算符赋值运算符其他运算符 1.1 算术运算符 操作符描述例子加法 - 相加运算符两侧的值A B 等于 30-减法 - 左操作数减去右操作数A – B 等于 -10*乘法 - 相乘操作符两侧的值A * B等于200/除法 - 左操作数除以右操作数B /…

Spring Cloud Sleuth(Micrometer Tracing +Zipkin)

分布式链路追踪 分布式链路追踪技术要解决的问题&#xff0c;分布式链路追踪&#xff08;Distributed Tracing&#xff09;&#xff0c;就是将一次分布式请求还原成调用链路&#xff0c;进行日志记录&#xff0c;性能监控并将一次分布式请求的调用情况集中展示。比如各个服务节…

关于我的编程语言——C/C++——第四篇(深入1)

&#xff08;叠甲&#xff1a;如有侵权请联系&#xff0c;内容都是自己学习的总结&#xff0c;一定不全面&#xff0c;仅当互相交流&#xff08;轻点骂&#xff09;我也只是站在巨人肩膀上的一个小卡拉米&#xff0c;已老实&#xff0c;求放过&#xff09; 字符类型介绍 char…

一台手机可以登录运营多少个TikTok账号?

很多TikTok内容创作者和商家通过运营多个账号来实现品牌曝光和产品销售&#xff0c;这种矩阵运营方式需要一定的技巧和设备成本&#xff0c;那么对于很多新手来说&#xff0c;一台手机可以登录和运营多少个TikTok账号呢&#xff1f; 一、运营TikTok账号的数量限制 TikTok的官…

DNS服务器部署

一、要求 1.搭建dns服务器能够对自定义的正向或者反向域完成数据解析查询。 2.配置从DNS服务器&#xff0c;对主dns服务器进行数据备份。 二、配置 1.搭建dns服务器能够对自定义的正向或者反向域完成数据解析查询。 &#xff08;1&#xff09;首先需要安装bind服务 &#xf…

三周精通FastAPI:28 构建更大的应用 - 多个文件

官方文档&#xff1a;https://fastapi.tiangolo.com/zh/tutorial/bigger-applications 更大的应用 - 多个文件 如果你正在开发一个应用程序或 Web API&#xff0c;很少会将所有的内容都放在一个文件中。 FastAPI 提供了一个方便的工具&#xff0c;可以在保持所有灵活性的同时…

【react使用AES对称加密的实现】

react使用AES对称加密的实现 前言使用CryptoJS库密钥存放加密方法解密方法结语 前言 项目中要求敏感信息怕被抓包泄密必须进行加密传输处理&#xff0c;普通的md5加密虽然能解决传输问题&#xff0c;但是项目中有权限的用户是需要查看数据进行查询的&#xff0c;所以就不能直接…

【STM32】INA3221三通道电压电流采集模块,HAL库

一、简单介绍 芯片的datasheet地址&#xff1a; INA3221 三通道、高侧测量、分流和总线电压监视器&#xff0c;具有兼容 I2C 和 SMBUS 的接口 datasheet (Rev. B) 笔者所使用的INA3221是淘宝买的模块 原理图 模块的三个通道的电压都是一样&#xff0c;都是POWER。这个芯片采用…

《机器人SLAM导航核心技术与实战》第1季:第10章_其他SLAM系统

视频讲解 【第1季】10.第10章_其他SLAM系统-视频讲解 【第1季】10.1.第10章_其他SLAM系统_RTABMAP算法-视频讲解 【第1季】10.2.第10章_其他SLAM系统_VINS算法-视频讲解 【第1季】10.3.第10章_其他SLAM系统_机器学习与SLAM-视频讲解 第1季&#xff1a;第10章_其他SLAM系统 …

《HelloGitHub》第 103 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

【OJ题解】C++实现反转字符串中的每个单词

&#x1f4b5;个人主页: 起名字真南 &#x1f4b5;个人专栏:【数据结构初阶】 【C语言】 【C】 【OJ题解】 题目要求&#xff1a;给定一个字符串 s &#xff0c;你需要反转字符串中每个单词的字符顺序&#xff0c;同时仍保留空格和单词的初始顺序。 题目链接: 反转字符串中的所…

Oracle OCP认证考试考点详解082系列09

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 41. 第41题&#xff1a; 题目 41.Examine the description of the EMPLOYEES table NLS_DATE_FORMAT is set to DD-MON-YY Which query…