【昕宝爸爸小模块】图文源码详解什么是线程池、线程池的底层到底是如何实现的

news2024/11/28 22:23:31

在这里插入图片描述

➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan


       欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。


       本文章CSDN首发,欢迎转载,要注明出处哦!


       先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复!


图文源码详解什么是线程池、线程池的底层到底是如何实现的

  • 一、✅引言
    • 1.1✅典型解析
    • 1.2✅线程池什么情况下使用
    • 1.3✅线程池的优缺点
  • 二、✅拓展知识仓
    • 2.1✅线程池的实现原理
    • 2.2✅添加一个任务
    • 2.3✅添加worker线程
    • 2.4✅worker线程处理队列任务
  • 三、✅总结
    • 3.1✅线程池参数
    • 3.2✅Executors
    • 3.3✅线程池相关


一、✅引言


1.1✅典型解析


线程池是池化技术的一种典型实现,所谓池化技术就是提前保存大量的资源,以备不时之需。在机器资源有限的情况下,使用池化技术可以大大的提高资源的利用率,提升性能等。


线程池,说的就是提前创建好一批线程,然后保存在线程池中,当有任务需要执行的时候,从线程池中选一个线程来执行任务。


在编程领域,比较典型的池化技术有:


线程池、连接池、内存池、对象池等


Java中线程池的继承关系如下:


在这里插入图片描述


1.2✅线程池什么情况下使用


线程池适合在以下情况下使用


1. 有大量短时间任务需要处理。如果每个任务都单独开一个线程,那么线程的创建、销毁与切换会消耗相当多的资源,而线程池可以重用已有的线程,从而减少这些开销。


2. 需要管理多个任务的执行顺序。线程池可以根据任务的优先级或提交时间等因素来调度任务的执行,从而更加稳定和可控。


3. 需要限制并发执行的任务数量。通过设置线程池的最大线程数量,可以保证同时执行的任务数不会超过设定值,从而避免系统资源被过度占用。


4. 需要异步执行任务,并获取任务的执行结果。线程池可以通过返回std::future对象来实现异步执行任务,并在需要时获取任务的执行结果。


5. 并发任务处理:线程池可以用于处理并发的任务,例如处理请求、批量处理数据、并行计算等。通过线程池,可以管理和复用线程,提高任务的执行效率。


6. 异步任务执行:线程池可以用于执行异步任务,将任务提交给线程池后,可以立即返回并继续执行后续代码,不必等待任务完成。适用于需要在后台执行耗时任务,同时不阻塞主线程的场景。


1.3✅线程池的优缺点


线程池是一种用于管理线程的机制,它可以在程序运行时创建一定数量的线程,并将这些线程放入线程池中以供复用。线程池可以有效地减少线程的创建和销毁开销,提高系统的性能和响应速度。下面是一些线程池的优缺点:


优点


  1. 降低资源消耗:线程池中的线程可以重复利用,避免了频繁地创建和销毁线程,从而降低了系统的开销。
  2. 提高响应速度:线程池可以预先创建一定数量的线程,当任务到达时可以直接使用这些线程,无需等待线程的创建,提高了系统的响应速度。
  3. 提高线程的可管理性:线程池可以进行统一的分配、调优和监控,方便对线程的管理和维护。
  4. 控制并发数:线程池可以限制任务的并发执行数量,避免了过多的线程导致系统资源的耗尽。
  5. 提供任务队列:线程池可以配合任务队列使用,缓冲尚未执行的任务,避免了任务因为线程不够而被拒绝执行的情况。

缺点


  1. 无法充分利用多核资源:由于线程数量有限,当线程数量过多时,可能会浪费系统资源,并且无法充分利用多核资源。
  2. 无法适应动态负载变化:线程池中的线程数量是固定的,因此在面对任务负载的动态变化时,线程池可能无法做到自适应调整。
  3. 无法处理无限制创建线程的情况:虽然线程池可以限制任务的并发数,但是如果程序中出现无限制创建线程的情况,线程池也无法解决该问题。
  4. 维护成本较高:如果线程池的大小设置不当或者调优不当,可能会导致系统性能的下降或者资源的浪费,需要进行相应的调整和维护。

二、✅拓展知识仓


2.1✅线程池的实现原理


通常,一般构造函数会反映出这个工具或这个对象的数据存储结构。


在这里插入图片描述

如果把线程池比作一个公司。公司会有正式员工处理正常业务,如果工作量大的话,会雇佣外包人来工作。




闲时就可以释放外包人员以减少公司管理开销。一个公司因为成本关系,雇佣的人员始终是有最大数。




如果这时候还有任务处理不过来,就走需求池排任务。


  1. acc: 获取调用上下文
  2. corePoolSize: 核心线程数量,可以类比正式员工数量,常驻线程数量
  3. maximumPoolSize: 最大的线程数量,公司最多雇佣员工数量。常驻+临时线程数量
  4. workQueue: 多余任务等待队列,再多的人都处理不过来了,需要等着,在这个地方等
  5. keepAliveTime: 非核心线程空闲时间,就是外包人员等了多久,如果还没有活干,解雇了
  6. threadFactory:创建线程的工厂,在这个地方可以统一处理创建的线程的属性。每个公司对员工的要求不一样,恩,在这里设置员工的属性。
  7. handler: 线程池拒绝策略,什么意思呢? 就是当任务实在是太多,人也不够,需求池也排满了还有任务咋办?默认是不处理,抛出异常告诉任务提交者,我这忙不过来了

2.2✅添加一个任务


接着,我们看一下线程池中比较重要的execute方法,该方法用于向线程池中添加一个任务。


在这里插入图片描述

核心模块用红框标记了:


  • 第一个红框: workerCount0f万法根据tl的低29位,得到线程池的当前线程数,如果线程数小于corePoolSize,则执行addWorker方法创建新的线程执行任务。

  • 第二个黄框:判断线程池是否在运行,如果在,任务队列是否允许插入,插入成功再次验证线程池是否运行,如果不在运行,移除插入的任务,然后抛出拒绝策略。如果在运行,没有线程了,就启用一个线程。

  • 第三个黄框: 如果添加非核心线程失败,就直接拒绝了。

这里逻辑稍微有点复杂,画了个流程图仅供参考:


在这里插入图片描述

接下来,我们看看如何添加一个工作线程的?


2.3✅添加worker线程


从方法 execute 的实现可以看出: addWorker 主要负责创建新的线程并执行任务,代码如下(这里代码有点长,没关系,也是分块的,总共有5个关键的代码块) :


在这里插入图片描述

  • 第一个红框 : 做是否能够添加工作线程条件过滤:

判断线程池的状态,如果线程池的状态值大于或等 SHUTDOWN,则不处理提交的任务,直接返回;


  • 第二个红框:做自旋,更新创建线程数量:

通过参数 core 判断当前需要创建的线程是否为核心线程,如果core为true,且当前线程数小于 corePoolSize ,则跳出循环,开始创建新的线程:


有人或许会疑问 retry 是什么? 这个是iava中的goto语法。只能运用在break和continue后面


接着看后面的代码:


在这里插入图片描述

  • 第一个红框: 获取线程池主锁。

线程池的工作线程通过Woker类实现,通过ReentrantLock锁保证线程安全。


  • 第二个红框: 添加线程到workers中 (线程池中)。
  • 第三个红框: 启动新建的线程。

接下来,我们看看workers是什么。


在这里插入图片描述

一个hashSet。所以,线程池底层的存储结构其实就是一个HashSet。


2.4✅worker线程处理队列任务


在这里插入图片描述

  1. 第一个红框: 是否是第一次执行任务,或者从队列中可以获取到任务。
  2. 第二个红框: 获取到任务后,执行任务开始前操作钩子。
  3. 第三个红框: 执行任务。
  4. 第四个红框: 执行任务后钩子。

这两人钩子 (beforeExecute,afterExecute) 允许我们自己继承线程池,做任务执行前后外理。


到这里,源代码分析到此为止。


三、✅总结


3.1✅线程池参数


通过上面的源码解析我们可以看到,线程池的参数主要包括以下七个:


  1. corePoolSize:线程池中的常驻核心线程数。
  2. maximumPoolSize:线程池能够容纳同时执行的最大线程数。此值必须大于等于1。
  3. keepAliveTime:多余的空闲线程存活时间。当空闲时间达到此值时,多余的线程会被销毁直到只剩下corePoolSize个线程为止。
  4. unit:keepAliveTime的时间单位,如秒、毫秒等。
  5. workQueue:任务队列,被提交但尚未被执行的任务。当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务。
  6. threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般用默认的即可。
  7. handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的数量最大线程数时如何来拒绝请求执行的runnable的策略。

3.2✅Executors


Executors的创建线程池的方法,创建出来的线程池都实现了ExecutorService接口。常用方法有以下几个:


newFixedThreadPool(int Threads): 创建固定数目线程的线程池;


newCachedThreadPool(): 创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果没有可用的线程,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60秒钟未被使用的线程。


newSingleThreadExecutor0创建一个单线程化的Executor。


newScheduledThreadPoolint corePoolSize)创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。


3.3✅线程池相关


所谓线程池本质是一个hashSet。多余的任务会放在阻塞队列中。


只有当阻塞队列满了后,才会触发非核心线程的创建。所以非核心线程只是临时过来打杂的。直到空闲了,然后自己关闭了。


线程池提供了两个钩子(beforeExecute,afterExecute) 给我们,我们继承线程池,在执行任务前后做一些事情。


线程池原理关键技术: 锁 (lock,cas)阻塞队列hashSet (资源池)


在这里插入图片描述

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

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

相关文章

【送书活动七期】CMeet系列 技术生态沙龙:技术人职业交流会·杭州场-转鸿蒙 对应用开发来说是否是职业发展新机会

CSDN致力于促进城市区域内尖端新兴技术开发者交流,提供开放自由的切磋平台。在近期热议的话题中,“华为鸿蒙系统不再兼容安卓应用”的消息成了程序员们广泛关注并引发思考的问题。 因此便有了我们此次的活动探讨议题! 目录 题外话开场简单介绍活动主办方介绍活动话题讨论升职加…

Intewell-Win_V2.0.1_release版本正式发布

Intewell-Win_V2.0.1_release版本 版本号:V2.0.1 版本发布类型:release正式版本 版本特点 1.优化虚拟网卡使用 2.实时性优化 运行环境推荐 Intewell developer可以运行在windows7及windows10 64位 支持硬件列表

小程序系列--7.页面配置以及网络数据请求

一. 页面配置 1.页面配置文件的作用 小程序中,每个页面都有自己的 .json 配置文件,用来对当前页面的窗口外观、页面效果等进行配置。 2. 页面配置和全局配置的关系 3. 页面配置中常用的配置项 二、网络数据请求 1. 小程序中网络数据请求的限制 2. 配…

2024年美赛数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法,就是频繁模…

rust跟我学三:文件时间属性获得方法

图为RUST吉祥物 大家好,我是get_local_info作者带剑书生,这里用一篇文章讲解get_local_info是怎样获得杀毒软件的病毒库时间的。 首先,先要了解get_local_info是什么? get_local_info是一个获取linux系统信息的rust三方库,并提供一些常用功能,目前版本0.2.4。详细介绍地址…

AI大模型学习笔记之二:什么是 AI 大模型的训练和推理?

在人工智能(AI)的领域中,我们经常听到训练(Training) 和 推理(Inference) 这两个词汇,它们是构建强大 AI 模型的关键步骤。我们通过类比人类的学习过程来理解这两个概念,可以更加自然而生动地理…

详解React与Vue的性能对比

React 和 Vue 是当前最流行的前端开发框架之一。它们都具有高度的灵活性和可扩展性,但在某些方面有所不同。在本篇文章中,我将详细介绍 React 和 Vue 这两个技术,并比较它们的优点和缺点。 目录 1. React: 1.1 优点: …

杨中科 .NETCORE EFCORE第七部分 一对一,多对多

一对一 一对一关系配置 1、builder.HasOne(o >o.Delivery).WithOne(d>d.Order).HasForeignKey(d>dOrderId); 2、测试插入和获取数据 示例 新建 Order 新建 Delivery DeliveryConfig OrderConfig 执行 迁移命令 查看数据库 测试数据插入 运行查看数据 多对多…

Redis 服务器 命令

目录 1.Redis Client Pause 命令 - 在指定时间内终止运行来自客户端的命令简介语法可用版本: > 2.9.50返回值: 返回 OK。如果 timeout 参数是非法的返回错误。 示例 2.Redis Debug Object 命令 - 获取 key 的调试信息简介语法可用版本: > 1.0.0返回值: 当 key 存在时&…

在程序中链接静态库 和 动态库

9. 链接库 在编写程序的过程中,可能会用到一些系统提供的动态库或者自己制作出的动态库 或者静态库文件,cmake中也为我们提供了相关的加载动态库的命令hehedalinux:~/Linux/loveDBTeacher-v3$ tree . ├── CMakeLists.txt ├── include │ └── …

无法打开浏览器开发者工具的可能解决方法

网页地址: https://jx.xyflv.cc/?url视频地址url 我在抖音里面抓了一个视频地址, 获取到响应的json数据, 找到里面的视频地址信息 这个网站很好用: https://www.jsont.run/ 可以使用js语法对json对象操作, 找到所有视频的url地址 打开网页: https://jx.xyflv.cc/?urlhttps:…

k8s集群环境搭建以及插件安装

前置条件 终端工具MobaXterm很好用。 1、虚拟机三台(ip按自己的网络环境相应配置)(master/node) 节点ipk8s-master192.168.200.150k8s-node1192.168.200.151k8s-node2192.168.200.152 2、关闭防火墙(master/node) systemctl stop firewalld systemc…

python调用windows弹窗

python调用windows弹窗 import win32api import _thread # 引入线程的模块 比较老的模块 新的 threadingdef run(i):win32api.MessageBox(0, "您的{}号大宝贝上线了".format(i), "来自小莹的问候", 2)for i in range(5):_thread.start_new_thread(run…

入门指南:使用STM32微控制器进行ADC数据采集

使用STM32微控制器进行ADC(模数转换器)数据采集是嵌入式系统开发中常见的任务。本文将介绍如何通过STM32CubeMX和HAL库函数进行ADC数据采集,并提供相应的代码示例。 1. STM32CubeMX配置 首先,使用STM32CubeMX工具配置STM32微控制…

一条sql是如何运行的

在我们平时使用sql的时候,基本是基于黑盒的使用方式,在客户端输入一条sql语句,然后回显想要的数据,对于mysql server端内部如何运行的以及与存储引擎如何交互的不得而知。 通过下面一幅图,大致描述客户端和服务端交互…

【数据结构】归并排序的两种实现方式与计数排序

前言:在前面我们讲了各种常见的排序,今天我们就来对排序部分收个尾,再来对归并排序通过递归和非递归的方法进行实现,与对计数排序进行简单的学习。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏…

计算机服务器中了lockbit3.0勒索病毒如何处理,勒索病毒解密数据恢复

近期,网络上的勒索病毒非常猖狂,给企业的生产运营带来了极大困难,网络技术的发展为企业的生产运营提供了极大便利,但也为企业的数据安全带来严重威胁。经过云天数据恢复中心对近期lockbit3.0勒索病毒解密,为大家整理了…

基于生成模板的动态前缀微调事件抽取(ACL2022)

1、写作动机: 尽管将事件抽取任务转换为具有提示的序列生成问题越来越多,但基于生成的方法仍存在两个重大挑战,包括使用欠佳的提示和静态事件类型信息。 欠佳的提示:手动为每种事件类型设计提示,没有调优&#xff0c…

数据库的安全管理

数据库的安全管理 一、实验目的 掌握用户账号的创建、查看、修改、删除的方法。掌握用户权限设置方法。掌握角色的创建、删除方法。 二、实验内容用户账号的创建、查看、修改、删除的SQL语句。用户权限设置SQL语句。角色的创建、删除SQL语句。 三、实验步骤在本地主机创建用户…

代码随想录-刷题第五十七天

42. 接雨水 题目链接:42. 接雨水 思路:本题十分经典,使用单调栈需要理解的几个问题: 首先单调栈是按照行方向来计算雨水,如图: 使用单调栈内元素的顺序 从大到小还是从小到大呢? 从栈头&…