【从零开始学习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.将本地代码库与远…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

