【从零开始学习JAVA | 第四十篇】了解线程池
目录
前言:
线程池:
线程池的工作流程:
代码实现线程池:
任务拒绝策略:
线程池多大才算合适?
总结:
前言:
在Java编程中,线程池是一个强大的工具,它能够管理和复用线程,提供高效的并发处理能力。通过线程池,我们可以有效地控制并发线程的数量,并降低线程创建和销毁的开销。本文将引导你深入了解Java中的线程池,探索其原理、用法和优势,为你提供一个更高效的编程方式。

线程池的作用就是管理线程数量,减少线程频繁的创建和销毁
线程池:
线程池是一种用于管理和复用线程的技术,它可以有效地处理并发任务并提高程序的性能和响应能力。线程池维护着一个线程队列,其中包含了一定数量的线程。当有新的任务到达时,线程池会从队列中选择一个空闲的线程来执行任务,而不是为每个任务都创建新的线程。
线程池的工作流程:
-
创建线程池,包括初始化线程队列和创建指定数量的线程。
-
将任务提交给线程池。可以通过将任务对象提交给线程池的方式来添加新的任务。
-
线程池从任务队列中选择一个空闲的线程来执行任务。
-
执行任务。线程池中的线程会执行任务对象中定义的操作。
-
任务执行完成后,线程返回线程池并等待下一个任务。
-
线程池继续从任务队列中选择新的任务并分配给空闲线程,循环执行以上步骤。

代码实现线程池:
1.创建线程池的工具类 ExecutorService:
- public static ExecutorService newCachedThreadPool() 创建一个没有上限的线程池
- public static ExecutorService newCachedThreadPool(int int nthread) 创建一个有上限的线程池
其实第一个创建线程池不是真正没有上限,他的上限是int的最大范围,只不过因为实在是太大了,因此我们说没有上限。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {// 创建一个固定大小为5的线程池ExecutorService threadPool = Executors.newFixedThreadPool(5);// 提交任务给线程池for (int i = 0; i < 10; i++) {final int taskId = i;threadPool.execute(new Runnable() {public void run() {try {System.out.println("开始执行任务:" + taskId);Thread.sleep(2000); // 模拟任务执行时间System.out.println("任务执行完成:" + taskId);} catch (InterruptedException e) {e.printStackTrace();}}});}// 关闭线程池threadPool.shutdown();}
}
小技巧:
通过打断点的方式,我们可以实时看到当前线程池中的线程数量:
2.自定义创建线程池对象 ThreadPoolExecutor:
在Java中,我们可以使用ThreadPoolExecutor来自定义创建线程池对象。ThreadPoolExecutor是ExecutorService接口的一个实现类,它允许我们灵活地配置线程池的核心线程数、最大线程数、线程存活时间等参数。
首先,我们需要导入java.util.concurrent包。然后,可以通过以下代码创建一个自定义的线程池对象:
public class test03 {public static void main(String[] args) {ThreadPoolExecutor pool = new ThreadPoolExecutor(3,//核心线程数量6,//最大线程数60,//空闲线程最大存活时间TimeUnit.SECONDS,//时间单位new ArrayBlockingQueue<>(3),//指定任务队列最大长度Executors.defaultThreadFactory(),//创建线程工厂new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略);}
}
在上述代码中,我们传入了核心线程数、最大线程数、非核心线程空闲超时时间以及任务队列等参数来创建线程池对象。你还可以根据需要,调整这些参数以满足你的实际需求。
核心线程数(corePoolSize):核心线程数是线程池中一直存活的线程数量。当提交一个任务时,如果当前核心线程数还未达到设定的值,线程池会创建新的核心线程来处理任务。即使核心线程处于空闲状态,它们也不会被回收。
最大线程数(maxPoolSize):最大线程数是线程池中能容纳的最大线程数量。当提交的任务超过了核心线程数并且任务队列已满时,线程池会创建新的线程来执行任务,直到达到最大线程数。超过最大线程数的任务将会被拒绝执行。
非核心线程空闲超时时间(keepAliveTime):当线程池中的线程数量超过核心线程数,并且这些线程处于空闲状态时,非核心线程会被回收。空闲超时时间设定了非核心线程的最长存活时间,超过这个时间,空闲的非核心线程将被回收。
任务拒绝策略:
在Java中,任务拒绝策略用于处理线程池无法接受更多任务时的行为。当线程池已满并且工作队列已满或达到最大容量时,新提交的任务可能会被拒绝执行。Java提供了四种默认的任务拒绝策略:
-
AbortPolicy(中止策略):这是默认的任务拒绝策略。当线程池无法接受新任务时,新提交的任务会立即抛出RejectedExecutionException异常。
-
CallerRunsPolicy(调用者运行策略):如果线程池无法接受新任务,则由提交任务的线程来执行该任务。这意味着任务的执行将回退到调用线程中执行,从而降低了整体的并发度。
-
DiscardPolicy(丢弃策略):当线程池无法接受新任务时,新提交的任务将被静默丢弃,不会抛出任何异常。这意味着被丢弃的任务将不会被执行。
-
DiscardOldestPolicy(丢弃最旧策略):当线程池无法接受新任务时,线程池会丢弃工作队列中最旧的任务(即最先提交的任务),然后尝试再次提交新任务。
除了这四种默认的拒绝策略外,还可以通过实现RejectedExecutionHandler接口来自定义任务拒绝策略。通过实现该接口,可以定义自己的拒绝策略逻辑,例如将被拒绝的任务记录下来或将其放入其他队列中等。然后,可以将自定义的拒绝策略传递给线程
在自定义线程池中,我们需要掌握好自定义过程中的七个参数的意义。
线程池多大才算合适?
线程池大小的计算是有计算公式的,在介绍计算公式之前,我们要先讲解一下什么是最大并行数
最大并行数指的是在给定的系统环境下同时执行的最大线程或任务数。
线程池大小计算公式:
1.CPU密集型运算:
在CPU密集型运算中,任务主要是由CPU执行,涉及较少的I/O操作。在这种情况下,线程池的大小可以通过以下公式计算:
最大并行数+1
2.I/O密集型运算:
在I/O密集型运算中,任务涉及大量的I/O操作,例如读取文件、网络通信等。在这种情况下,由于任务执行时间中有很多时间被阻塞在I/O等待上,可以通过以下公式计算线程池的大小:
Nthreads = Ncpu * Ucpu * (1 + (W/C))
Nthreads是线程池中的线程数。Ncpu是计算机中的CPU核心数。Ucpu是期望的CPU利用率(0 <= Ucpu <= 1)。它表示期望的CPU工作时间与总时间的比例。W/C通常设置为较大的值,以便在I/O等待期间可以让CPU执行其他任务。
在I/O密集型任务中,通过增加线程池的大小可以更好地利用I/O等待的时间,提高整体的并发性能。然而,过量的线程数也会增加上下文切换的开销,因此需要根据实
总结:
今天我们学习了线程池的使用,学习了调用库类实现线程池以及自定义线程池。而多线程的内容其实并没有介绍完毕,我们将会在后面详细的介绍线程中比较重要的乐观锁以及悲观锁,还有大名鼎鼎的CAS算法。
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

相关文章:
【从零开始学习JAVA | 第四十篇】了解线程池
目录 前言: 线程池: 线程池的工作流程: 代码实现线程池: 任务拒绝策略: 线程池多大才算合适? 总结: 前言: 在Java编程中,线程池是一个强大的工具,它能…...
axios如何取消请求,其原理是什么?
axios 可以通过创建一个 CancelToken 来取消一个请求,基本原理是: 创建一个 CancelToken 的实例,它有一个 executor 函数,可以通过调用 executor 参数中的 cancel 函数来取消请求。在 axios 请求配置中指定 cancelToken 属性,将 CancelToken 实例传递进去。当我们需要取消请求…...
消息中间件 Asio (C++)
折腾了一上午,看到这个结果的时候泪目了兄弟闷,讲真。我的asio客户端成功收到服务端发来的消息了。虽然这确实是极其智障又简单的入门哈哈 下载独立版本 asio网络通信库新建cmake工程,CMakeLists.txt加载asioasio最简单的服务端和客户端代码…...
3.4 网络安全管理设备
数据参考:CISP官方 目录 IDS (入侵检测系统)网络安全审计漏洞扫描系统VPN(虚拟专网)堡垒主机安全管理平台 一、IDS (入侵检测系统) 入侵检测系统(IDS)是一种网络安全设备,用于监测和检测网络中的入侵行…...
前端高级面试题-JS
1. 原型 / 构造函数 / 实例 原型( prototype ): ⼀个简单的对象,⽤于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个 JavaScript 对象中都包含⼀个__proto__ (⾮标准)的属性指向它爹(该对象的原型),可 obj.p…...
AcWing 1564:哈希 ← 只具有正增量的二次探测法
【题目来源】https://www.acwing.com/problem/content/1566/【题目描述】 将一个由若干个不同正整数构成的整数序列插入到一个哈希表中,然后输出输入数字的位置。 哈希函数定义为 H(key)key%TSize,其中 TSize 是哈希表的最大大小。 利用只具有正增量的二…...
什么是媒体代发布?媒体代发布注意事项
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 媒体代发布是指将新闻稿或其他宣传内容委托给专业的媒体代理机构或公司进行发布和推广的活动。这些机构通常拥有丰富的媒体资源、人脉和经验,能够更好地将信息传递给目标受众…...
docker版jxTMS使用指南:使用jxTMS采集数据之二
本文是如何用jxTMS进行数据采集的第二部分,整个系列的文章请查看:docker版jxTMS使用指南:4.4版升级内容 docker版本的使用,请查看:docker版jxTMS使用指南 4.0版jxTMS的说明,请查看:4.0版升级内…...
系列六、Springboot操作RocketMQ
一、同步消息 1.1、发送&接收简单消息 1.1.1、发送简单消息 /*** 测试发送简单消息*/ Test public void sendSimpleMessage() {SendResult result rocketMQTemplate.syncSend("BOOT_TOPIC_SIMPLE", "我是一个简单消息");// 往[BOOT_TOPIC_SIMPLE]主…...
【jupyter异常错误】Kernel started:No module named ipykernel_launcher
尝试过的方案 pip install ipykernel 执行之后提示已经安装,但是执行代码依然报错 解决方案 python -m pip install ipykernel -U --force-reinstall 相当于是强制重新安装 安装成功后没有报错 注:根本原因应该是原来安装的包存在问题,虽然检测出来已经存在…...
使用langchain与你自己的数据对话(五):聊天机器人
之前我已经完成了使用langchain与你自己的数据对话的前四篇博客,还没有阅读这四篇博客的朋友可以先阅读一下: 使用langchain与你自己的数据对话(一):文档加载与切割使用langchain与你自己的数据对话(二):向量存储与嵌入使用langc…...
爬虫与搜索引擎优化:通过Python爬虫提升网站搜索排名
作为一名专业的爬虫程序员,我深知网站的搜索排名对于业务的重要性。在如今竞争激烈的网络世界中,如何让自己的网站在搜索引擎结果中脱颖而出,成为关键。今天,和大家分享一些关于如何通过Python爬虫来提升网站的搜索排名的技巧和实…...
2024软考系统架构设计师论文写作要点
一、写作注意事项 系统架构设计师的论文题目对于考生来说,是相对较难的题目。一方面,考生需要掌握论文题目中的系统架构设计的专业知识;另一方面,论文的撰写需要结合考生自身的项目经历。因此,如何将自己的项目经历和专业知识有机…...
【Maven】依赖范围、依赖传递、依赖排除、依赖原则、依赖继承
【Maven】依赖范围、依赖传递、依赖排除、依赖原则、依赖继承 依赖范围 依赖传递 依赖排除 依赖原则 依赖继承 依赖范围 在Maven中,依赖范围(Dependency Scope)用于控制依赖项在编译、测试和运行时的可见性和可用性。通过指定适当的依赖…...
数组slice、splice字符串substr、split
一、定义 这篇文章主要对数组操作的两种方法进行介绍和使用,包括:slice、splice。对字符串操作的两种方法进行介绍和使用,包括:substr、split (一)、数组 slice:可以操作的数据类型有:数组字符串 splice:数组 操作数组…...
程序漏洞:安全威胁的隐患
在当今数字化时代,计算机程序是现代社会的核心基石。然而,随着技术的进步,程序漏洞也成为了一个不可忽视的问题。程序漏洞可能导致数据泄露、系统崩溃、恶意攻击和经济损失等一系列问题。本文将深入探讨程序漏洞的定义、分类、影响和预防措施…...
0基础学C#笔记09:希尔排序法
文章目录 前言一、希尔排序的思想二、使用步骤总结 前言 希尔排序可以说是插入排序的一种变种。无论是插入排序还是冒泡排序,如果数组的最大值刚好是在第一位,要将它挪到正确的位置就需要 n - 1 次移动。也就是说,原数组的一个元素如果距离它…...
DOCKER的容器
1. 什么是Container(容器) 要有Container首先要有Image,也就是说Container是通过image创建的。 Container是在原先的Image之上新加的一层,称作Container layer,这一层是可读可写的(Image是只读的࿰…...
跳跃游戏——力扣55
文章目录 题目描述解法一 贪心题目描述 解法一 贪心 bool canJump(vector<int>& nums){int n=nums....
将本地项目上传至gitee的详细步骤
将本地项目上传至gitee的详细步骤 1.在gitee上创建以自己项目名称命名的空项目2.进入想上传的项目的文件夹,然后右键点击3. 初始化本地环境,把该项目变成可被git管理的仓库4.添加该项目下的所有文件5.使用如下命令将文件添加到仓库中去6.将本地代码库与远…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
break 语句和 continue 语句
break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...
day51 python CBAM注意力
目录 一、CBAM 模块简介 二、CBAM 模块的实现 (一)通道注意力模块 (二)空间注意力模块 (三)CBAM 模块的组合 三、CBAM 模块的特性 四、CBAM 模块在 CNN 中的应用 一、CBAM 模块简介 在之前的探索中…...
Qt/C++学习系列之列表使用记录
Qt/C学习系列之列表使用记录 前言列表的初始化界面初始化设置名称获取简单设置 单元格存储总结 前言 列表的使用主要基于QTableWidget控件,同步使用QTableWidgetItem进行单元格的设置,最后可以使用QAxObject进行单元格的数据读出将数据进行存储。接下来…...

