线程池使用之自定义线程池
目录
一: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号工作人员继续待着(池内保持核心线程数量);
三:线程池工作流程总结示意图
四:自定义线程池-参数设计分析
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);}}
}
相关文章:
线程池使用之自定义线程池
目录 一:Java内置线程池原理剖析 二:ThreadPoolExecutor参数详解 三:线程池工作流程总结示意图 四:自定义线程池-参数设计分析 1:核心线程数(corePoolSize) 2:任务队列长度(workQueue) 3:最大线程数(maximumPoolSize) 4:最…...
Puppeteer无头浏览器:开启自动化之门,掌握浏览器世界的无限可能
大概还是入门期,我曾用Puppeteer做爬虫工具以此来绕过某网站的防爬机制。近期有需求要做任意链接网页截图,像这种场景非常适合用Puppeteer完成。无头浏览器我已知的还有Selenium。 完成截图需求踩的最大的坑不是具体的逻辑代码,而是Docker部…...
Ubuntu 23.10/24.04 LTS 放弃默认使用 snap 版 CUPS 打印堆栈
导读Canonical 的开发者、OpenPrinting 的项目负责人 Till Kamppeter 今年 5 月表示,计划在 Ubuntu 23.10(Mantic Minotaur)上默认使用 Snap 版本的 CUPS 打印堆栈。 不过经过数月的测试,官方放弃了这项决定。Ubuntu 23.10&#x…...
Linux CentOS7 history命令
linux查看历史命令可以使用history命令,该命令可以列出所有已键入的命令。 这个命令的作用可以让用户或其他有权限人员,进行审计,查看已录入的命令。 用户所键入的命令作为应保存的信息将记录在文件中,这个文件就是家目录中的一…...
XC5350A 单节锂电池保护芯片 过放2.9V/2.8V/2.4V保护IC
XC5350A产品是一个高集成度的鲤离子/聚合物电池保护解决方案。XC5350A包含先进的功率MOSFET,高精度电压检测电路和延迟电路XC5350A放入一个超小型SOT23-5封装,只有一个外部元件使其成为在电池组有限的空间的理想解决方案。 XC5350A具有包括过充ÿ…...
单片机论文参考:1、基于单片机的电子琴
摘要 随着社会的发展进步,音乐逐渐成为我们生活中很重要的一部分,有人曾说喜欢音乐的人不会向恶。我们都会抽空欣赏世界名曲,作为对精神的洗礼。本论文设计一个基于单片机的简易电子琴。电子琴是现代电子科技与音乐结合的产物,是一…...
Opencv源码解析(2)算法
目录 一,直方图均衡 1,直方图统计 2,灰度变换 3,直方图均衡 二,可分离滤波器 1,可分离滤波器的工厂 2,ocvSepFilter、sepFilter2D 3,Sobel 三,相位相关法 phase…...
让Mac菜单栏变得更加美观整洁——Bartender 5
Bartender 5是一款Mac电脑上的菜单栏图标管理软件,能够帮助您把菜单栏上的图标整理得更加美观、整洁和易于使用。如果您的菜单栏上充斥着许多图标,导致视觉上很不舒适和疲劳,那么Bartender 5就是解决这一问题的最佳选择! Bartend…...
服务器迁移:无缝过渡指南
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
安卓开发中ViewBinding的使用
在安卓开发中,ViewBing 的作用就是简化 findViewById() 代码的写法。 看看下面的替换: etbinding.text //etfindViewById(R.id.text) 下面就看看怎么用的, 首先,打开app模块的build.gradle,然后添加如下代码&…...
【初阶数据结构】树(tree)的基本概念——C语言
目录 一、树(tree) 1.1树的概念及结构 1.2树的相关概念 1.3树的表示 1.4树在实际中的运用(表示文件系统的目录树结构) 二、二叉树的概念及结构 2.1二叉树的概念 2.2现实中真正的二叉树 2.3特殊的二叉树 2.4二叉树的性质…...
二叉树知识点
1.霍夫曼编码 这位作者写的很清楚 哈夫曼编码详解——图解真能看了秒懂_已知字符集abcdef,若各字符出现的次数_Young_IT的博客-CSDN博客 2.满二叉树与完全二叉树 满二叉树是指每层数量是pow(2,n-1)个节点,总节点数是pow(2,n)-1; 而完全二叉树是指最后一层不一定…...
Day69:283. 移动零、11. 盛最多水的容器、42. 接雨水
283. 移动零 leetcode链接:https://leetcode.cn/problems/move-zeroes/ 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。示例 1:…...
tensorrt的安装和使用
安装 提前安装好 CUDA 和 CUDNN,登录 NVIDIA 官方网站下载和主机 CUDA 版本适配的 TensorRT 压缩包即可。 以 CUDA 版本是 10.2 为例,选择适配 CUDA 10.2 的 tar 包,然后执行类似如下的命令安装并测试: #安装c版本 cd /the/pat…...
电压放大器在电子测试中的应用有哪些方面
电压放大器是一种常见的电子设备,广泛应用于各种测试和测量应用中。以下是电压放大器在电子测试中的几个主要方面应用的简要介绍。 信号采集与处理:电压放大器通常用于信号采集和处理,在测试过程中将低电平信号放大到适合进一步处理或分析的水…...
39.地址算术运算
如果p是一个指向数组中某个元素的指针,那么p将会对p进行自增运算并指向下一个元素,而pi将对p进行加i的增量运算,使其指向指针p当前所指向的元素之后的第i个元素。这类运算时指针或地址算术运算中最简单的形式。 allocbuf中的空间使用状况也是…...
没有外网的麒麟系统上搭建GitLab服务并且无需客户端账号密码验证
要在没有外网的麒麟系统上搭建GitLab服务并且无需客户端账号密码验证,可以按照以下步骤进行操作: 安装必要的依赖包和软件 sudo yum install curl policycoreutils-python openssh-server openssh-clients sudo systemctl enable sshd sudo systemctl …...
微服务生态系统:使用Spring Cloud构建分布式系统
文章目录 什么是微服务?为什么选择Spring Cloud?Spring Cloud的关键组件示例:构建一个简单的微服务步骤1:创建Spring Boot项目步骤2:配置Eureka服务发现步骤3:创建REST控制器步骤4:运行项目步骤…...
DIY 一个汽车方向盘游戏外设(MMOS OSW DIY)
OSW-MMOS直驱方向盘DIY过程记录 - 简书 (jianshu.com) DIY 一个汽车方向盘游戏外设(MMOS OSW DIY) 首先讲一下这个直驱系统大概的框架,首先是电脑,电脑里装MMOS的软件(这个软件国内高手把它汉化了的),电脑通过USB线&a…...
校园网络技术需求分析
路由技术: 路由协议工作在 OSI 参考模型的第 3 层,因此它的作用主要是在通信 子网间路由数据包。路由器具有在网络中传递数据时选择最佳路径的能力。 除了可以完成主要的路由任务,利用访问控制列表(Access Control List&#x…...
计算机网络(二):TCP篇
文章目录 1. TCP头部包含哪些内容?2. 为什么需要 TCP 协议? TCP 工作在哪一层?3. 什么是 TCP ?4. 什么是 TCP 连接?5. 如何唯一确定一个 TCP 连接呢?6. UDP头部大小是多少?包含哪些内容…...
测试登录界面:Python
import unittest from selenium import webdriver class LoginTest(unittest.TestCase): def setUp(self): self.driver webdriver.Chrome() def test_login(self): # 打开登录页面 self.driver.get("http://example.com/login") # 输入用户名和密码 user…...
Rust踩雷笔记(7)——两个链表题例子初识裸指针
目录 leetcode 234leetcode 19 leetcode 234 题目在这https://leetcode.cn/problems/palindrome-linked-list/,leetcode 234的回文链表,思路很简单,就是fast和slow两个指针,fast一次移动两个、slow一次一个,最后slow指…...
用什么命令看Linux系统的体系架构
要查看Linux系统的体系架构,可以使用uname命令。在终端中运行以下命令: uname -m该命令将返回系统的体系架构,例如x86_64表示64位系统,i686表示32位系统。 uname 使用方法 uname命令用于获取操作系统的相关信息。它可以用于显示…...
消息中间件大揭秘:选择之前你必须知道的关键信息
Hello大家好!我是小米,很高兴再次和大家见面!今天的话题非常精彩,我们将深入探讨消息中间件,并了解一些常见的消息队列:RabbitMQ、RocketMQ、Kafka以及Redis。如果你正在准备面试,或者只是对这些…...
【Unity基础】4.动画Animation
【Unity基础】4.动画Animation 大家好,我是Lampard~~ 欢迎来到Unity基础系列博客,所学知识来自B站阿发老师~感谢 (一)Unity动画编辑器 (1)Animation组件 这一张我们要学习如何在unity编辑器中&…...
FreeRTOS移植以及核心功能
文章目录 freertos和ucos区别,优缺点比较移植步骤核心功能内存管理(5种内存管理策略)FreeRTOS任务调度算法有三种时间管理通信管理 栈管理 freertos和ucos区别,优缺点比较 FreeRTOS(Free Real-Time Operating System&…...
重装系统(配置环境)
这里写目录标题 0.重装系统1.python1.1 anaconda1.2 pycharm1.3 深度学习环境配置 2.java2.1.安装JDK2.2.配置JDK环境变量2.3IDEA2.4 Maven 3.大数据3.1 虚拟机3.2 Hadoop平台3.3 存储3.4 采集3.5 计算3.6 查询3.7 可视化 0.重装系统 // An highlighted block var foo bar;1.…...
docker系列-报错以及解决指南
1. windows运行docker报错Windows Hypervisor is not presentDocker Desktop is unable to detect a Hypervisor.Hardware assisted virtualization and data execution protection must be enabled in the BIOS. Docker Desktop - Windows Hypervisor is not presentDocker D…...
Vue3快速上手
1.Vue3简介 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址:Release v3.0.0 One Piece vuejs/core GitHub 2.Vue3带…...
云南5个中风险地区/汕头自动seo
Camtasia 9 录制屏幕软件,并且有丰富的专业剪辑功能. 转载于:https://www.cnblogs.com/langhaoabcd/p/10446132.html...
wordpress默认模版在哪/如何联系百度推广
让MySQL支持Emoji表情,涉及无线相关的 MySQL 数据库建议都提前采用 utf8mb4 字符集。 mysql 版本 5.6 1 解决方案:将Mysql的编码从utf8转换成utf8mb4。 需要 > MySQL 5.5.3版本、从库也必须是5.5的了、低版本不支持这个字符集、复制报错 2 my.cnf 文…...
网站设计与网页配色实例精讲/百度公司怎么样
8.2 这几天晚上总是聊到很晚 偏偏生物钟很准时。 早上起来像是要去世了 早自习学英语,从基础开始学 中午起床之后头痛欲裂 晚自习的时候一边做题一边听心灵鸡汤 真正厉害的人,从不轻易放纵自己 课间看小胖和zzh打篮球, 我估计我是被秀了 周六…...
自己做书画交易网站/电销外包团队在哪找
【现象】 原因是{}导致的 【解决方法】 logger.info(f接口地址:/user/dashboard/getBaseCount ,请求参数:{},返回结果:{result}) 修改为: logger.info(f接口地址:/user/dashboard/getBaseCount ,请求参数:,返回结果:{result})...
网站如何做链接/热搜榜排名今日
嗨喽,大家好!我是舌尖尝美食,“尝遍人间百味,每样都很对胃”,每天亲手为家人做美食,享受健康美味的食物,今天分享给大家的是一道“腌芥菜”,喜欢这道菜的朋友欢迎关注我。导语&#…...