手动创建线程池各个参数的意义?

今天我们学习线程池各个参数的含义,并重点掌握线程池中线程是在什么时机被创建和销毁的。

线程池的参数

首先,我们来看下线程池中各个参数的含义,如表所示线程池主要有 6 个参数,其中第 3 个参数由 keepAliveTime + 时间单位组成。我们逐一看下它们各自的含义,corePoolSize 是核心线程数,也就是常驻线程池的线程数量,与它对应的是 maximumPoolSize,表示线程池最大线程数量,当我们的任务特别多而 corePoolSize 核心线程数无法满足需求的时候,就会向线程池中增加线程,以便应对任务突增的情况。

线程创建的时机

接下来,我们来具体看下这两个参数所代表的含义,以及线程池中创建线程的时机。如上图所示,当提交任务后,线程池首先会检查当前线程数,如果此时线程数小于核心线程数,比如最开始线程数量为 0,则新建线程并执行任务,随着任务的不断增加,线程数会逐渐增加并达到核心线程数,此时如果仍有任务被不断提交,就会被放入 workQueue 任务队列中,等待核心线程执行完当前任务后重新从 workQueue 中提取正在等待被执行的任务。

此时,假设我们的任务特别的多,已经达到了 workQueue 的容量上限,这时线程池就会启动后备力量,也就是 maximumPoolSize 最大线程数,线程池会在 corePoolSize 核心线程数的基础上继续创建线程来执行任务,假设任务被不断提交,线程池会持续创建线程直到线程数达到 maximumPoolSize 最大线程数,如果依然有任务被提交,这就超过了线程池的最大处理能力,这个时候线程池就会拒绝这些任务,我们可以看到实际上任务进来之后,线程池会逐一判断 corePoolSize、workQueue、maximumPoolSize,如果依然不能满足需求,则会拒绝任务。

corePoolSize 与 maximumPoolSize

通过上面的流程图,我们了解了 corePoolSize 和 maximumPoolSize 的具体含义,corePoolSize 指的是核心线程数,线程池初始化时线程数默认为 0,当有新的任务提交后,会创建新线程执行任务,如果不做特殊设置,此后线程数通常不会再小于 corePoolSize ,因为它们是核心线程,即便未来可能没有可执行的任务也不会被销毁。随着任务量的增加,在任务队列满了之后,线程池会进一步创建新线程,最多可以达到 maximumPoolSize 来应对任务多的场景,如果未来线程有空闲,大于 corePoolSize 的线程会被合理回收。所以正常情况下,线程池中的线程数量会处在 corePoolSize 与 maximumPoolSize 的闭区间内。

“长工”与“临时工”

我们可以把 corePoolSize 与 maximumPoolSize 比喻成长工与临时工,通常古代一个大户人家会有几个固定的长工,负责日常的工作,而大户人家起初肯定也是从零开始雇佣长工的。假如长工数量被老爷设定为 5 人,也就对应了 corePoolSize,不管这 5 个长工是忙碌还是空闲,都会一直在大户人家待着,可到了农忙或春节,长工的人手显然就不够用了,这时就需要雇佣更多的临时工,这些临时工就相当于在 corePoolSize 的基础上继续创建新线程,但临时工也是有上限的,也就对应了 maximumPoolSize,随着农忙或春节结束,老爷考虑到人工成本便会解约掉这些临时工,家里工人数量便会从 maximumPoolSize 降到 corePoolSize,所以老爷家的工人数量会一致保持在 corePoolSize 和 maximumPoolSize 的区间。

在这里我们用一个动画把整个线程池变化过程生动地描述出来,比如线程池的 corePoolSize 为 5,maximumPoolSize 为 10,任务队列容量为 100,随着任务被提交,我们的线程数量会从 0 慢慢增长到 5,然后就不再增长了,新的任务会被放入队列中,直到队列被塞满,然后在 corePoolSize 的基础上继续创建新线程来执行队列中的任务,线程会逐渐增加到 maximumPoolSize, 然后线程数不再增加,如果此时仍有任务被不断提交,线程池就会拒绝任务。随着队列中任务被执行完,被创建的 10 个线程现在无事可做了,这时线程池会根据 keepAliveTime 参数来销毁线程,已达到减少内存占用的目的。

通过对流程图的理解和动画演示,我们总结出线程池的几个特点。

  • 线程池希望保持较少的线程数,并且只有在负载变得很大时才增加线程。

  • 线程池只有在任务队列填满时才创建多于 corePoolSize 的线程,如果使用的是无界队列(例如 LinkedBlockingQueue),那么由于队列不会满,所以线程数不会超过 corePoolSize。

  • 通过设置 corePoolSize 和 maximumPoolSize 为相同的值,就可以创建固定大小的线程池。

  • 通过设置 maximumPoolSize 为很高的值,例如 Integer.MAX_VALUE,就可以允许线程池创建任意多的线程。

keepAliveTime+时间单位

第三个参数是 keepAliveTime + 时间单位,当线程池中线程数量多于核心线程数时,而此时又没有任务可做,线程池就会检测线程的 keepAliveTime,如果超过规定的时间,无事可做的线程就会被销毁,以便减少内存的占用和资源消耗。如果后期任务又多了起来,线程池也会根据规则重新创建线程,所以这是一个可伸缩的过程,比较灵活,我们也可以用 setKeepAliveTime 方法动态改变 keepAliveTime 的参数值。

ThreadFactory

第四个参数是 ThreadFactory,ThreadFactory 实际上是一个线程工厂,它的作用是生产线程以便执行任务。我们可以选择使用默认的线程工厂,创建的线程都会在同一个线程组,并拥有一样的优先级,且都不是守护线程,我们也可以选择自己定制线程工厂,以方便给线程自定义命名,不同的线程池内的线程通常会根据具体业务来定制不同的线程名。

workQueue 和 Handler

最后两个参数是 workQueue 和 Handler,它们分别对应阻塞队列和任务拒绝策略;

  1. 第一种拒绝策略是 AbortPolicy,这种拒绝策略在拒绝任务时,会直接抛出一个类型为 RejectedExecutionException 的 RuntimeException,让你感知到任务被拒绝了,于是你便可以根据业务逻辑选择重试或者放弃提交等策略。

  2. 第二种拒绝策略是 DiscardPolicy,这种拒绝策略正如它的名字所描述的一样,当新任务被提交后直接被丢弃掉,也不会给你任何的通知,相对而言存在一定的风险,因为我们提交的时候根本不知道这个任务会被丢弃,可能造成数据丢失。

  3. 第三种拒绝策略是 DiscardOldestPolicy,如果线程池没被关闭且没有能力执行,则会丢弃任务队列中的头结点,通常是存活时间最长的任务,这种策略与第二种不同之处在于它丢弃的不是最新提交的,而是队列中存活时间最长的,这样就可以腾出空间给新提交的任务,但同理它也存在一定的数据丢失风险。

  4. 第四种拒绝策略是 CallerRunsPolicy,相对而言它就比较完善了,当有新任务提交后,如果线程池没被关闭且没有能力执行,则把这个任务交于提交任务的线程执行,也就是谁提交任务,谁就负责执行任务。这样做主要有两点好处。

  • 第一点新提交的任务不会被丢弃,这样也就不会造成业务损失。
  • 第二点好处是,由于谁提交任务谁就要负责执行任务,这样提交任务的线程就得负责执行任务,而执行任务又是比较耗时的,在这段期间,提交任务的线程被占用,也就不会再提交新的任务,减缓了任务提交的速度,相当于是一个负反馈。在此期间,线程池中的线程也可以充分利用这段时间来执行掉一部分任务,腾出一定的空间,相当于是给了线程池一定的缓冲期。
    在这里插入图片描述

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

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

相关文章

【Linux】linuxCNC+Qt+Opencascade+kdl+hal 实时6轴机器人控制器

CNC机器人 程序框架 机器人模型 笔记: debian重启后 无法打开共享目录 最新版搜狗输入法安装后不支持中文,需要安装旧版本的 sogoupinyin_4.0.1.2800_x86_64.deb可用 数控机器人在哪些领域应用有优势 数控机器人在多个领域都展现出了显著的优势&#xff…

PyQt4应用程序的PDF查看器

最近因为项目需要创建一个基于PyQt4的PDF查看器应用程序,正常来说,我们可以使用PyQt4的QtWebKit模块来显示PDF文件。那么具体怎么实现呢 ?以下就是我写的一个简单的示例代码,演示如何创建一个PyQt4应用程序的PDF查看器&#xff1a…

MySQL order by 语句执行流程

全字段排序 假设这个表的部分定义是这样的: CREATE TABLE t (id int(11) NOT NULL,city varchar(16) NOT NULL,name varchar(16) NOT NULL,age int(11) NOT NULL,addr varchar(128) DEFAULT NULL,PRIMARY KEY (id),KEY city (city) ) ENGINEInnoDB; 有如下 SQL 语…

网络分段增强网络安全的 6 种方法

网络违规事件日益增多。因此,实施更强大的网络安全策略以保护敏感数据免受恶意攻击变得至关重要。 其中一种技术是网络分段。它涉及将大型计算机网络架构划分为较小的、隔离的独立子网,以便在入侵者闯入时整个网络不受影响。 因此,实施网络…

CSS基本选择器

文章目录 1. ID 选择器1.1. 语法1.2. 完整写法 2. 类选择器2.1. 语法2.2. 完整写法 3. 元素选择器4. 通配选择器5. 基本选择器优先级6. 基本选择器的总结7. Google 案例 1. ID 选择器 以 # 开头,后面跟着 ID 名称,根据元素的 ID 名称选择元素&#xff0…

BBS模型层搭建

BBS模型层搭建 目录 BBS模型层搭建建表思想配置文件模型层User应用:Blog应用:Article应用: 建表思想 配置文件 settings.py: # 默认用户模型指定 AUTH_USER_MODEL User.Userinfo底部添加即可,用于替换默认的Abstrac…

冒泡排序,详详解解

目录 基本概念: 上图: 核心思路: 基本步骤: 关键: 代码核心: 补充: 代码(规范) : 代码(优化): 今天我们不刷力扣了&…

HTML5、CSS3面试题(二)

上一章:HTML5、CSS3面试题(一) 哪些是块级元素那些是行内元素,各有什么特点 ?(必会) 行内元素: a、span、b、img、strong、input、select、lable、em、button、textarea 、selecting 块级元素&#xff1…

L1 - 006 连续因子

思路:1.要求最长的连续因子序列,我们需要知道序列的长度和序列的起点。 2.对于起点 i 来说,他不能超过 n 的平方根,在循环时从 2 到 sqrt(n) 。用到变量:记录个数num,起点start,最大个数maxnum…

Qt篇——QChartView获取鼠标停留位置的数值

需求:鼠标停留在QChartView上时,想要计算停留位置的数值。 一开始的方法是想要通过鼠标移动事件计算鼠标在QChartView上的坐标,在换算成数值,后来发现QChartView中除了图表数据,还有坐标轴与坐标轴数值标签占了高度&a…

基于单片机的车载酒精含量自检系统设计与实现

摘要:调查显示,大约50%的交通事故与酒后驾车有关,酒后驾车已成为车祸致死的首要原因。为从根本上杜绝酒后驾车,设计了一款基于STC89C52 单片机的车载酒精含量自检系统,该系统能很好地解决酒驾问题,控制简单、使用方便,具有很好的应用价值。 关键词:STC89C52 单片机;车…

JavaEE企业开发新技术2

目录 2.7 Field类的基本概念 文字性概念描述: Field类 2.8 Field的基本操作-1 2.9 Field的基本操作-2 分析: 2.10 Field 的综合练习 总结: 和equals的区别: 使用 比较 使用equals比较 2.7 Field类的基本概念 文字性…

.NET高级面试指南专题十七【 策略模式模式介绍,允许在运行时选择算法的行为】

介绍: 策略模式是一种行为设计模式,它允许在运行时选择算法的行为。它定义了一系列算法,将每个算法封装到一个对象中,并使它们可以互相替换。这使得算法可独立于使用它的客户端变化。 原理: 策略接口(Strat…

CVPR2024 | 大核卷积新高度101x101,美团提出PeLK

https://arxiv.org/pdf/2403.07589.pdf 本文概述 最近,一些大核卷积网络以吸引人的性能和效率进行了反击。然而,考虑到卷积的平方复杂度,扩大内核会带来大量的参数,而大量的参数会引发严重的优化问题。由于这些问题,当…

安卓之四大组件

组件描述Activity(活动)在应用中的一个Activity可以用来表示一个界面,意思可以理解为“活动”,即一个活动开始,代表 Activity组件启动,活动结束,代表一个Activity的生命周期结束。一个Android应用必须通过Activity来运…

Xcode 15.3 Archive失败

Xcode 15.3 Archive失败 背景 升级 Xcode 到 15.3,真机运行正常。打包的时候发现 Archive 失败。 提示: Call parameter type does not match function signature! 仔细看报错里是和HandyJSON相关的提示。 解决 起初以为和 Pod 库有关系,…

docker容器启动rabbitmq

docker容器启动rabbitmq 一、RabbitMQ部署1.1.在线拉取mq镜像1.2.运行mq容器1.3.访问mq 二、RabbitMQ的集群2.1.集群分类2.1.设置 /etc/hosts文件 endl 一、RabbitMQ部署 1.1.在线拉取mq镜像 # 在线拉取 docker pull rabbitmq:3-management1.2.运行mq容器 docker run \ -e R…

Kafka-生产者报错javax.management.InstanceAlreadyExistsException

生产者发送消息到 kafka 中,然后控制台报错 然后根据日志查看 kafka 的源码发现了问题原因 说的是MBean已经注册了,然后报异常了,这样就会导致生产者的kafka注册失败, 原因是项目上生产者没有配置clientId,默认都是空导致的, 多个生产者(项目)注册到kafka集群中的 id 都相同。 …

微服务分布式基于Springcloud的拍卖管理系统597wx

越来越多的用户利用互联网获得信息,但各种信息鱼龙混杂,信息真假难以辨别。为了方便用户更好的获得信息,因此,设计一种安全高效的拍卖管理系统极为重要。 为设计一个安全便捷,并且使用户更好获取拍卖管理系统&#xff…

探寻殷墟文化,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建殷墟考古场景下的甲骨文字符检测识别分析系统

甲骨文是一种非常历史悠久的古老文字,在前面我们基本上很少有涉及这块的内容,最近正好在做文字相关的项目开发研究,就想着基于甲骨文的场景来开发对应的检测识别系统,在前文中我们基于系列YOLO算法模型开发构建了在仿真数据实验场…