当前位置: 首页 > news >正文

线程池使用之自定义线程池

目录

一:Java内置线程池原理剖析

二:ThreadPoolExecutor参数详解

三:线程池工作流程总结示意图

四:自定义线程池-参数设计分析

1:核心线程数(corePoolSize)

2:任务队列长度(workQueue)

3:最大线程数(maximumPoolSize)

4:最大空闲时间(keepAliveTime)

五:自定义线程池-实现步骤

1:编写任务类(MyTask),实现Runnable接口;

2:编写线程类(MyWorker),用于执行任务,需要持有所有任务;

3:编写线程池类(MyThreadPool),包含提交任务,执行任务的能力;

4:编写测试类(MyTest),创建线程池对象,提交多个任务测试;


一:Java内置线程池原理剖析

              我们要想自定义线程池,必须先了解线程池的工作原理,才能自己定义线程池;这里我们通过观察java中ThreadPoolExecutor的源码来学习线程池的原理

构造方法:
public ThreadPoolExecutor(int corePoolSize, //核心线程数量int maximumPoolSize,//     最大线程数long keepAliveTime, //       最大空闲时间TimeUnit unit,         //        时间单位BlockingQueue<Runnable> workQueue,   //   任务队列ThreadFactory threadFactory,    // 线程工厂RejectedExecutionHandler handler  //  饱和处理机制) 
{ ... }

二:ThreadPoolExecutor参数详解

我们可以通过下面的场景理解ThreadPoolExecutor中的各个参数;

a客户(任务)去银行(线程池)办理业务,但银行刚开始营业,窗口服务员还未就位(相当于线程池中初始线程数量为0),

于是经理(线程池管理者)就安排1号工作人员(创建1号线程执行任务)接待a客户(创建线程);

在a客户业务还没办完时,b客户(任务)又来了,于是经理(线程池管理者)就安排2号工作人员(创建2号线程执行任务)接待b客户(创建了一个新的线程);假设该银行总共就2个窗口(核心线程数量是2);

紧接着在a,b客户都没有结束的情况下c客户来了,于是经理(线程池管理者)就安排c客户先坐到银行大厅的座位上(空位相当于是任务队列)等候,

并告知他: 如果1、2号工作人员空出,c就可以前去办理业务;

此时d客户又到了银行,(工作人员都在忙,大厅座位也满了)于是经理赶紧安排临时工(新创建的线程)在大堂站着,手持pad设备给d客户办理业务;

假如前面的业务都没有结束的时候e客户又来了,此时正式工作人员都上了,临时工也上了,座位也满了(临时工加正式员工的总数量就是最大线程数),

于是经理只能按《超出银行最大接待能力处理办法》(饱和处理机制)拒接接待e客户;

最后,进来办业务的人少了,大厅的临时工空闲时间也超过了1小时(最大空闲时间),经理就会让这部分空闲的员工人下班.(销毁线程)

但是为了保证银行银行正常工作(有一个allowCoreThreadTimeout变量控制是否允许销毁核心线程,默认false),即使正式工闲着,也不得提前下班,所以1、2号工作人员继续待着(池内保持核心线程数量);

三:线程池工作流程总结示意图

四:自定义线程池-参数设计分析

             通过观察 Java 中的内置线程池参数讲解和线程池工作流程总结 , 我们不难发现 , 要设计一个好的线程池 , 就必须合理的设置线程池的 4 个参数 ; 那到底该如何合理的设计 4 个参数的值呢 ? 我们一起往下看 .
4 个参数的设计 :

1:核心线程数(corePoolSize)

  核心线程数的设计需要依据任务的处理时间和每秒产生的任务数量来确定,例如:执行一个任务需要0.1,系统百分之80的时间每秒都会产生100个任务,那么要想在1秒内处理完这100个任务,就需要10个线程,此时我们就可以设计核心线程数为10;当然实际情况不可能这么平均,所以我们一般按照8020原则设计即可,既按照百分之80的情况设计核心线程数,剩下的百分之20可以利用最大线程数处理;

2:任务队列长度(workQueue)

  任务队列长度一般设计为:核心线程数/单个任务执行时间*2即可;例如上面的场景中,核心线程数设计为10,单个任务执行时间为0.1,则队列长度可以设计为200;

3:最大线程数(maximumPoolSize)

  最大线程数的设计除了需要参照核心线程数的条件外,还需要参照系统每秒产生的最大任务数决定:例如:上述环境中,如果系统每秒最大产生的任务是1000,那么,最大线程数=(最大任务数-任务队列长度)*单个任务执行时间;: 最大线程数=(1000-200)*0.1=80;

4:最大空闲时间(keepAliveTime)

  这个参数的设计完全参考系统运行环境和硬件压力设定,没有固定的参考值,用户可以根据经验和系统产生任务的时间间隔合理设置一个值即可;

上面4个参数的设置只是一般的设计原则,并不是固定的,用户也可以根据实际情况灵活调整!

五:自定义线程池-实现步骤

1:编写任务类(MyTask),实现Runnable接口;

/*需求:自定义线程池练习,这是任务类,需要实现Runnable;包含任务编号,每一个任务执行时间设计为0.2秒*/
public class MyTask implements Runnable{private int id;//由于run方法是重写接口中的方法,因此id这个属性初始化可以利用构造方法完成public MyTask(int id) {this.id = id;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println("线程:"+name+" 即将执行任务:"+id);try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程:"+name+" 完成了任务:"+id);}@Overridepublic String toString() {return "MyTask{" +"id=" + id +'}';}
}

2:编写线程类(MyWorker),用于执行任务,需要持有所有任务;

/*需求:编写一个线程类,需要继承Thread类,设计一个属性,用于保存线程的名字;设计一个集合,用于保存所有的任务;*/
public class MyWorker extends Thread{private String name;//保存线程的名字private List<Runnable> tasks;//利用构造方法,给成员变量赋值public MyWorker(String name, List<Runnable> tasks) {super(name);this.tasks = tasks;}@Overridepublic void run() {//判断集合中是否有任务,只要有,就一直执行任务while (tasks.size()>0){Runnable r = tasks.remove(0);r.run();}}
}

3:编写线程池类(MyThreadPool),包含提交任务,执行任务的能力;

/*这是自定义的线程池类;成员变量:1:任务队列   集合  需要控制线程安全问题2:当前线程数量3:核心线程数量4:最大线程数量5:任务队列的长度成员方法1:提交任务;将任务添加到集合中,需要判断是否超出了任务总长度2:执行任务;判断当前线程的数量,决定创建核心线程还是非核心线程*/
public class MyThreadPool {// 1:任务队列   集合  需要控制线程安全问题private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());//2:当前线程数量private int num;//3:核心线程数量private int corePoolSize;//4:最大线程数量private int maxSize;//5:任务队列的长度private int workSize;public MyThreadPool(int corePoolSize, int maxSize, int workSize) {this.corePoolSize = corePoolSize;this.maxSize = maxSize;this.workSize = workSize;}//1:提交任务;public void submit(Runnable r){//判断当前集合中任务的数量,是否超出了最大任务数量if(tasks.size()>=workSize){System.out.println("任务:"+r+"被丢弃了...");}else {tasks.add(r);//执行任务execTask(r);}}//2:执行任务;private void execTask(Runnable r) {//判断当前线程池中的线程总数量,是否超出了核心数,if(num < corePoolSize){new MyWorker("核心线程:"+num,tasks).start();num++;}else if(num < maxSize){new MyWorker("非核心线程:"+num,tasks).start();num++;}else {System.out.println("任务:"+r+" 被缓存了...");}}}

4:编写测试类(MyTest),创建线程池对象,提交多个任务测试;

/*测试类:1: 创建线程池类对象;2: 提交多个任务*/
public class MyTest {public static void main(String[] args) {//1:创建线程池类对象;MyThreadPool pool = new MyThreadPool(2,4,20);//2: 提交多个任务for (int i = 0; i <30 ; i++) {//3:创建任务对象,并提交给线程池MyTask my = new MyTask(i);pool.submit(my);}}
}

相关文章:

线程池使用之自定义线程池

目录 一&#xff1a;Java内置线程池原理剖析 二&#xff1a;ThreadPoolExecutor参数详解 三&#xff1a;线程池工作流程总结示意图 四&#xff1a;自定义线程池-参数设计分析 1:核心线程数(corePoolSize) 2:任务队列长度(workQueue) 3:最大线程数(maximumPoolSize) 4:最…...

Puppeteer无头浏览器:开启自动化之门,掌握浏览器世界的无限可能

大概还是入门期&#xff0c;我曾用Puppeteer做爬虫工具以此来绕过某网站的防爬机制。近期有需求要做任意链接网页截图&#xff0c;像这种场景非常适合用Puppeteer完成。无头浏览器我已知的还有Selenium。 完成截图需求踩的最大的坑不是具体的逻辑代码&#xff0c;而是Docker部…...

Ubuntu 23.10/24.04 LTS 放弃默认使用 snap 版 CUPS 打印堆栈

导读Canonical 的开发者、OpenPrinting 的项目负责人 Till Kamppeter 今年 5 月表示&#xff0c;计划在 Ubuntu 23.10&#xff08;Mantic Minotaur&#xff09;上默认使用 Snap 版本的 CUPS 打印堆栈。 不过经过数月的测试&#xff0c;官方放弃了这项决定。Ubuntu 23.10&#x…...

Linux CentOS7 history命令

linux查看历史命令可以使用history命令&#xff0c;该命令可以列出所有已键入的命令。 这个命令的作用可以让用户或其他有权限人员&#xff0c;进行审计&#xff0c;查看已录入的命令。 用户所键入的命令作为应保存的信息将记录在文件中&#xff0c;这个文件就是家目录中的一…...

XC5350A 单节锂电池保护芯片 过放2.9V/2.8V/2.4V保护IC

XC5350A产品是一个高集成度的鲤离子/聚合物电池保护解决方案。XC5350A包含先进的功率MOSFET&#xff0c;高精度电压检测电路和延迟电路XC5350A放入一个超小型SOT23-5封装&#xff0c;只有一个外部元件使其成为在电池组有限的空间的理想解决方案。 XC5350A具有包括过充&#xff…...

单片机论文参考:1、基于单片机的电子琴

摘要 随着社会的发展进步&#xff0c;音乐逐渐成为我们生活中很重要的一部分&#xff0c;有人曾说喜欢音乐的人不会向恶。我们都会抽空欣赏世界名曲&#xff0c;作为对精神的洗礼。本论文设计一个基于单片机的简易电子琴。电子琴是现代电子科技与音乐结合的产物&#xff0c;是一…...

Opencv源码解析(2)算法

目录 一&#xff0c;直方图均衡 1&#xff0c;直方图统计 2&#xff0c;灰度变换 3&#xff0c;直方图均衡 二&#xff0c;可分离滤波器 1&#xff0c;可分离滤波器的工厂 2&#xff0c;ocvSepFilter、sepFilter2D 3&#xff0c;Sobel 三&#xff0c;相位相关法 phase…...

让Mac菜单栏变得更加美观整洁——Bartender 5

Bartender 5是一款Mac电脑上的菜单栏图标管理软件&#xff0c;能够帮助您把菜单栏上的图标整理得更加美观、整洁和易于使用。如果您的菜单栏上充斥着许多图标&#xff0c;导致视觉上很不舒适和疲劳&#xff0c;那么Bartender 5就是解决这一问题的最佳选择&#xff01; Bartend…...

服务器迁移:无缝过渡指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

安卓开发中ViewBinding的使用

在安卓开发中&#xff0c;ViewBing 的作用就是简化 findViewById() 代码的写法。 看看下面的替换&#xff1a; etbinding.text //etfindViewById(R.id.text) 下面就看看怎么用的&#xff0c; 首先&#xff0c;打开app模块的build.gradle&#xff0c;然后添加如下代码&…...

【初阶数据结构】树(tree)的基本概念——C语言

目录 一、树&#xff08;tree&#xff09; 1.1树的概念及结构 1.2树的相关概念 1.3树的表示 1.4树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 二、二叉树的概念及结构 2.1二叉树的概念 2.2现实中真正的二叉树 2.3特殊的二叉树 2.4二叉树的性质…...

二叉树知识点

1.霍夫曼编码 这位作者写的很清楚 哈夫曼编码详解——图解真能看了秒懂_已知字符集abcdef,若各字符出现的次数_Young_IT的博客-CSDN博客 2.满二叉树与完全二叉树 满二叉树是指每层数量是pow(2,n-1)个节点&#xff0c;总节点数是pow(2,n)-1; 而完全二叉树是指最后一层不一定…...

Day69:283. 移动零、11. 盛最多水的容器、42. 接雨水

283. 移动零 leetcode链接&#xff1a;https://leetcode.cn/problems/move-zeroes/ 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。示例 1:…...

tensorrt的安装和使用

安装 提前安装好 CUDA 和 CUDNN&#xff0c;登录 NVIDIA 官方网站下载和主机 CUDA 版本适配的 TensorRT 压缩包即可。 以 CUDA 版本是 10.2 为例&#xff0c;选择适配 CUDA 10.2 的 tar 包&#xff0c;然后执行类似如下的命令安装并测试&#xff1a; #安装c版本 cd /the/pat…...

电压放大器在电子测试中的应用有哪些方面

电压放大器是一种常见的电子设备&#xff0c;广泛应用于各种测试和测量应用中。以下是电压放大器在电子测试中的几个主要方面应用的简要介绍。 信号采集与处理&#xff1a;电压放大器通常用于信号采集和处理&#xff0c;在测试过程中将低电平信号放大到适合进一步处理或分析的水…...

39.地址算术运算

如果p是一个指向数组中某个元素的指针&#xff0c;那么p将会对p进行自增运算并指向下一个元素&#xff0c;而pi将对p进行加i的增量运算&#xff0c;使其指向指针p当前所指向的元素之后的第i个元素。这类运算时指针或地址算术运算中最简单的形式。 allocbuf中的空间使用状况也是…...

没有外网的麒麟系统上搭建GitLab服务并且无需客户端账号密码验证

要在没有外网的麒麟系统上搭建GitLab服务并且无需客户端账号密码验证&#xff0c;可以按照以下步骤进行操作&#xff1a; 安装必要的依赖包和软件 sudo yum install curl policycoreutils-python openssh-server openssh-clients sudo systemctl enable sshd sudo systemctl …...

微服务生态系统:使用Spring Cloud构建分布式系统

文章目录 什么是微服务&#xff1f;为什么选择Spring Cloud&#xff1f;Spring Cloud的关键组件示例&#xff1a;构建一个简单的微服务步骤1&#xff1a;创建Spring Boot项目步骤2&#xff1a;配置Eureka服务发现步骤3&#xff1a;创建REST控制器步骤4&#xff1a;运行项目步骤…...

DIY 一个汽车方向盘游戏外设(MMOS OSW DIY)

OSW-MMOS直驱方向盘DIY过程记录 - 简书 (jianshu.com) DIY 一个汽车方向盘游戏外设&#xff08;MMOS OSW DIY&#xff09; 首先讲一下这个直驱系统大概的框架&#xff0c;首先是电脑&#xff0c;电脑里装MMOS的软件(这个软件国内高手把它汉化了的)&#xff0c;电脑通过USB线&a…...

校园网络技术需求分析

路由技术&#xff1a; 路由协议工作在 OSI 参考模型的第 3 层&#xff0c;因此它的作用主要是在通信 子网间路由数据包。路由器具有在网络中传递数据时选择最佳路径的能力。 除了可以完成主要的路由任务&#xff0c;利用访问控制列表&#xff08;Access Control List&#x…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

python基础语法Ⅰ

python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器&#xff0c;来进行一些算术…...

HTML中各种标签的作用

一、HTML文件主要标签结构及说明 1. <&#xff01;DOCTYPE html> 作用&#xff1a;声明文档类型&#xff0c;告知浏览器这是 HTML5 文档。 必须&#xff1a;是。 2. <html lang“zh”>. </html> 作用&#xff1a;包裹整个网页内容&#xff0c;lang"z…...