多线程JUC:线程池原理、自定义线程池详细解析

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:多线程&JUC:等待唤醒机制(生产者消费者模式)
📚订阅专栏:多线程&JUC
希望文章对你们有所帮助

线程池是一个比较好玩的东西,在做项目的过程中多少也是接触过的,在高并发的任务执行过程中就会经常自行创建线程池。在这里梳理一下线程池的原理,并且进行实践。

线程池原理、自定义线程池详细解析

  • 线程池
  • 自定义线程池详细解析
  • 最大并行数
  • 线程池多大合适

线程池

在之前的多线程程序中,我们需要一个线程进行工作,就需要创建出一个线程对象,等到线程对象的任务执行完毕以后,线程就会自动被回收消失,这种方式其实并不好,这会浪费我们操作系统的资源。

线程池的主要核心:

1、创建一个池子,池子是空的
2、提交任务时,池子会创建新的线程对象,任务执行完毕不会销毁,而是归还给池子。下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
3、如果提交任务时,线程池没有空闲线程,就会创建新的线程,不过这有一定的上限,达到上限则无法继续创建新线程,任务就会排队等待

线程池的代码实现:

1、创建线程池
2、提交任务(底层自动完成创建新线程或复用线程)
3、所有的任务全部执行完毕,关闭线程池

创建线程池可以使用工具类Executors,通过调用方法返回不同类型的线程池对象:

方法名称说明
public static ExecutorService newCachedThreadPool()创建一个没有上限的线程池
public static ExecutorService newFixedThreadPool(int nThreads)创建有上限的线程池

一般还是会创建有上限的线程池。

MyRunnable:

public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "@" + i);}}
}

测试类:

public class MyThreadPoolDemo {public static void main(String[] args) {//获取线程池对象ExecutorService pool1 = Executors.newFixedThreadPool(3);//提交任务给线程池pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());//销毁线程池pool1.shutdown();}
}

调试的时候也可以看到,当提交完4个任务以后,就会有一个任务是无法执行的,即等待状态:
在这里插入图片描述

自定义线程池详细解析

Executors自带的两个方法创建线程池很方便,但是不够灵活,因此要掌握如何自定义一个线程池对象。
查看newFixedThreadPool的底层源码,其创建了ThreadPoolExecutor对象,这个就是线程池对象,参数很复杂,所以可以稍微看一下它的英文讲解:
在这里插入图片描述
最好的方式就是举个例子:

将线程池当作一个一对一服务的餐厅,即一个员工服务一名客户。
一般状态下,有一定数量的正式员工进行工作,但是当进店的顾客很多的时候,就需要招聘临时员工,若之后临时员工长时间不工作,就会解聘。
在餐厅爆满的时候,我们应该让客户排队等待,应该限定一个排队等待的客户数量,防止后续客户等待时间过长

这样的方式比起Executors中的方法会灵活很多,可以解析出7个核心元素:

1、正式员工数量
2、餐厅最大员工数(正式员工数+临时员工数)
3、临时员工空闲多长时间被辞退(值)
4、临时员工空闲多长时间被辞退(单位)
5、排队的客户
6、从哪里招人
7、当排队人数过多,超出客户拒绝服务

转化为线程池,就是以下7个核心元素:

1、核心线程数量
2、线程池中最大线程的数量
3、空闲时间(值)
4、空闲时间(单位)
5、阻塞队列
6、创建线程的方式
7、要执行的任务过多时的解决方案

基本元素上线程池与餐厅对应起来,但是线程池真正的执行流程和上面的餐厅还是有一些区别的,假设:核心线程:3 临时线程:3 队伍长度:3,有8个任务(1-8)需要执行,则1、2、3被3个核心线程执行,4、5、6排队等待,7、8被2个临时线程执行
也就是说,临时线程是在阻塞队列满了之后才会创建执行的,同时也说明了任务提交的顺序不代表执行的顺序,就如上述的7、8线程比4、5、6先进去线程池,自然也先执行。
若线程池完全满负荷工作(达到最大线程数,阻塞队列也满),则后面提交的任务就会出发任务拒绝策略,默认为舍弃任务并抛出异常。

		/*** 参数1:核心线程数量              不能小于0* 参数2、线程池中最大线程的数量      不能小于0,且线程最大数量≥核心线程数量* 参数3、空闲时间(值)            不能小于0* 参数4、空闲时间(单位)           用TimeUnit指定* 参数5、阻塞队列                 不能为null* 参数6、创建线程的方式            不能为null* 参数7、要执行的任务过多时的解决方案 不能为null*/ThreadPoolExecutor pool = new ThreadPoolExecutor(3,6,60,TimeUnit.SECONDS, //60Snew ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(), //默认方式创建new ThreadPoolExecutor.AbortPolicy() //默认方案,这是一个内部类);

这样就成功实现了线程池的自定义。

总结:不断的提交的任务会有以下三个临界点:

1、核心线程满时,再提交任务就会排队
2、核心线程满,队伍满时,会创建临时线程
3、核心线程满,队伍满,临时线程满时,会触发任务拒绝策略

最大并行数

可以自定义线程池,但是设置为多大是很重要的,它有一些计算公式,在学习计算公式前先了解何为最大并行数。

最大并行数,实际上和我们CPU的型号是有关系的,例如4核8线程的CPU,本地的相关信息是可以查看到的,但是它根本不会把本地的所有CPU资源都交给java虚拟机使用,因此想要查看java虚拟机的最大并行数可以通过写代码:

//getRuntime()获取到系统的运行环境,availableProcessors即可向java虚拟机返回可用处理器的数目
int count = Runtime.getRuntime().availableProcessors();
System.out.println(count);

我的电脑这边的最大并行数为12。

线程池多大合适

这其实是有计算公式的,不过得看项目是什么类型的:

1、CPU密集型运算:I/O操作少,计算多
2、I/O密集型运算:I/O操作多,计算少

在CPU密集型运算的项目中:
线程池大小 = 最大并行数 + 1 线程池大小 = 最大并行数 + 1 线程池大小=最大并行数+1
在I/O密集型运算的项目中:
线程池大小 = 最大并行数 ∗ 期望 C P U 利用率 ∗ 总时间 ( C P U 计算时间 + 等待时间 ) C P U 计算时间 线程池大小=最大并行数*期望CPU利用率*\frac{总时间(CPU计算时间+等待时间)}{CPU计算时间} 线程池大小=最大并行数期望CPU利用率CPU计算时间总时间(CPU计算时间+等待时间)

对于多线程,就先学这么多,乐观锁、CAS等在项目中用的不算太多,但是面试应该会经常问,需要去看一下面经。

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

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

相关文章

「优选算法刷题」:数青蛙

一、题目 给你一个字符串 croakOfFrogs&#xff0c;它表示不同青蛙发出的蛙鸣声&#xff08;字符串 "croak" &#xff09;的组合。由于同一时间可以有多只青蛙呱呱作响&#xff0c;所以 croakOfFrogs 中会混合多个 “croak” 。 请你返回模拟字符串中所有蛙鸣所需不…

Minecraft的红石教程之隐形门一号

一.前言 昨天写的&#xff0c;哦不&#xff0c;今天凌晨写的CSDN太烧脑了&#xff0c;今天玩会儿MinecraftA-A 二.一号隐形门 1.准备的材料&#xff1a; 粘性活塞&#xff0c;木板&#xff0c;红石&#xff0c;压力板&#xff0c;红石火把 2.挖洞 中间挖2*3*2的洞&#xf…

第三百一十七回

文章目录 1. 概念介绍2. 实现方法2.1 hintText2.2 labelText2.3 controller 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何在输入框中处理光标"相关的内容&#xff0c;本章回中将介绍如何添加输入框默认值.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.…

基于springboot广场舞团管理系统源码和论文

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

Java项目:19 基于SpringBoot的医院管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 医院管理系统 分为三个角色 管理员、医生、病人 管理员的主要功能&#xff1a;系统管理、医生管理、患者管理、预约管理、病史管理、住院信息管理、管…

【OrangePi Zero2 智能家居】阿里云人脸识别方案

一、接入阿里云 二、C语言调用阿里云人脸识别接口 三、System V消息队列和POSIX 消息队列 一、接入阿里云 在之前树莓派的人脸识别方案采用了翔云平台的方案去1V1上传比对两张人脸比对&#xff0c;这种方案是可行&#xff0c;可 以继续采用。但为了接触更多了云平台方案&…

Flink基础篇|001_Flink是什么

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注、&#x…

网络报文处理流程

报文处理流程 WLAN网络中的数据包括管理报文和业务数据报文。管理报文必须采用CAPWAP隧道进行转发&#xff0c;而业务数据报文除了可以采用CAPWAP隧道转发之外&#xff0c;还可以采用直接转发方式和Soft-GRE转发方式。 管理报文用来传送AC与AP之间的管理数据&#xff0c;存在于…

再识C语言 DAY16【进制的转换 】

文章目录 前言进制的转换一、各个进制的组成二、二进制转换其他进制三。其他进制转换为二进制四.小数部分进制转换五.八进制与十进制的相互转换 总如果您发现文章有错误请与我留言&#xff0c;感谢 前言 本文章总结于此视频 进制的转换 一、各个进制的组成 1. 二进制&#x…

【EAI 014】Gato: A Generalist Agent

论文标题&#xff1a;A Generalist Agent 论文作者&#xff1a;Scott Reed, Konrad Zolna, Emilio Parisotto, Sergio Gomez Colmenarejo, Alexander Novikov, Gabriel Barth-Maron, Mai Gimenez, Yury Sulsky, Jackie Kay, Jost Tobias Springenberg, Tom Eccles, Jake Bruce,…

【JAVA WEB】 css背景属性 圆角矩形的绘制

目录 背景属性设置 圆角矩形 背景属性设置 背景颜色,在style中 background-color:颜色&#xff1b; 背景图片 background-image:url(……) 背景图片的平铺方式 background-repeat: 平铺方式 repeat 平铺&#xff08;默认&#xff09;no-repeat 不平铺repeat-x 水平平铺repea…

例37:爱好选择

建立一个新的EXE工程&#xff0c;放两个单选&#xff0c;两个复选框如图33。 图33 输入代码&#xff1a; Sub Form1_Check1_BN_Clicked(hWndForm As hWnd, hWndControl As hWnd)Text1.Text ""If Check1.Value ThenText1.Text"你喜欢" & Check1.Cap…

【并发编程】锁-源码分析

1、ReentrantLock 1.1 加锁流程源码 1.1.1 加锁流程概述 1.1.2 lock源码分析 1.1.2.1 公平和非公平锁方式 // 非公平锁 final void lock() {// 上来就先基于CAS的方式,尝试将state从0改为1if (compareAndSetState(0, 1))// 获取锁资源成功,会将当前线程设置到exclusiveOwn…

【Go】一、Go语言基本语法与常用方法容器

GO基础 Go语言是由Google于2006年开源的静态语言 1972&#xff1a;&#xff08;C语言&#xff09; — 1983&#xff08;C&#xff09;—1991&#xff08;python&#xff09;—1995&#xff08;java、PHP、js&#xff09;—2005&#xff08;amd双核技术 web端新技术飞速发展&…

LLaMA 入门指南

LLaMA 入门指南 LLaMA 入门指南LLaMA的简介LLaMA模型的主要结构Transformer架构多层自注意力层前馈神经网络Layer Normalization和残差连接 LLaMA模型的变体Base版本Large版本Extra-Large版本 LLaMA模型的特点大规模数据训练 LLaMA模型常用数据集介绍公共数据来源已知的数据集案…

yolov8自制数据训练集

目录 1.YOLOv8是啥 2.系统环境 3.安装labelimg 3.1安装 3.2启动 labelimg 4.自制分类图片 4.1 YOLO数据集要求 4.2 图片保存目录 4.3 利用labelimg进行标注 4.4 存储图片 4.5 标注文件 5.数据集训练 5.1yaml文件 5.2训练命令 5.3查看训练过程 5.3.1启动tensorb…

拟合案例2:matlab实现分段函数拟合(分段点未知)及源码

案例介绍: 本案是针对一个分段函数中的参数进行拟合,使用的拟合工具是matlab中的lsqcurvefit或nlinfit。函数形式和待拟合参数如下所示。该案例的特殊之处在于分段点也是待拟合参数,因此如何自定义拟合函数,实现分段点的拟合是本案例最大的难点。本案例提供了三种分段函数…

Git基础命令,分支,标签的使用【快速入门Git】

Git基础命令&#xff0c;分支&#xff0c;标签的使用【快速入门Git】 Git基础常用命令Git工作流程工作区&#xff0c;暂存区和版本库文件状态获取Git仓库 git init | git clone查看文件状态 git status暂存已修改的文件 git add 查看已暂存和未暂存的修改 git diff提交文件更改…

第7章 智能租房——首页

学习目标 掌握房源总数展示功能&#xff0c;能够实现将统计的房源总数在首页中展示 掌握最新房源数据展示功能&#xff0c;能够实现将查询的最新房源数据在首页中展示 掌握热点房源数据展示功能&#xff0c;能够实现将查询的热点房源数据在首页中展示 了解智能提示搜索框的功…