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

【JavaEE】多线程案例-线程池

在这里插入图片描述

文章目录

  • 1. 什么是线程池
  • 2. 为什么要使用线程池(线程池有什么优点)
  • 3. 如何使用Java标准库提供的线程池
    • 3.1 创建一个线程池对象
    • 3.2 什么是工厂模式
    • 3.3 为什么要使用工厂模式
    • 3.4 Executors 创建不同具有不同特性的线程池
    • 3.5 ThreadPool 类的构造方法
    • 3.6 线程池的拒绝策略
    • 3.7 调用 submit 方法添加任务
  • 4. 自己实现一个线程池

1. 什么是线程池

线程池是一种多线程处理形式,它处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池中的线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。线程池避免了在处理短时间任务时创建与销毁线程的代价,从而提高了程序的效率和性能。

2. 为什么要使用线程池(线程池有什么优点)

我们都知道,在 Java 中使用多进程效率是比较低的,因为进程的创建和销毁的开销是比较大的,这样就会导致进程的创建和销毁的速度比较慢。所以在多进程的基础上就出现了线程。线程的创建和销毁都比较轻量,多个线程共用一套资源,这就避免了多次向计算机申请资源,极大提高了代码的执行速度。但是如果一个线程多次创建和销毁的话,也会导致系统资源的频繁调用,并且创建和销毁线程的而操作是内核态的,计算机通过调用相关的 API,然后进行线程的创建和销毁,但是既然是内核态操作,那么在计算机创建和销毁线程的过程中可能不是只干了这一件事,可能还会顺便帮其他线程提供资源等,这样就降低了代码的执行速度,所以为了解决线程多次创建和销毁,并且保证线程的创建和销毁属于用户态的操作的问题,就出现了线程池这一概念。在线程池中会提前创建 n 个线程,这些线程在执行完后不会销毁,而是继续存储在线程池当中等待下一次调用,正是因为线程池的这一概念,就使得线程创建和销毁的频率降低了。

总结来说,线程池的优点有以下这些:

  1. 降低资源消耗:通过重复利用已创建的线程,降低线程创建和销毁造成的消耗。
  2. 提高响应速度:当任务到达时,任务无需等待线程创建,可以立即执行。
  3. 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以进行统一的分配,调优和监控。
  4. 避免系统过度切换:如果不使用线程池,有可能会造成系统创建大量同类线程而导致消耗完内存或者产生“过度切换”的问题。

3. 如何使用Java标准库提供的线程池

3.1 创建一个线程池对象

在Java的 java.util.concurrent 包中提供了线程池相关的方法。那么如何创建出能执行线程池相关操作的对象呢?

ExecutorService service = Executors.newScheduledThreadPool(3);

在这里插入图片描述
ExecutorService 是Java中的一个接口,它继承了Executor接口。

ExecutorService 接口在 java.util.concurrent 包中,它用于管理线程池。它提供了一种方式来管理和控制线程的生命周期。具体来说,它用于创建和管理线程池,可以执行线程,也可以关闭线程池。

Executors 则是一个工厂类,用来创建不同类型的 ThreadPoolExecutor 实例。

看到工厂类就需要提到一个常用的模式——工厂模式了,那么什么又是工厂模式呢?

3.2 什么是工厂模式

工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式,通过将对象的实例化过程封装在工厂类中,使得创建对象的方式更加灵活和可扩展。

在工厂模式中,客户端代码只需关注接口,而无需关注对象的具体创建过程。工厂模式通过提供一个统一的接口来创建不同类型的对象,这个接口定义了创建对象的标准方式。

在这里插入图片描述

3.3 为什么要使用工厂模式

工厂模式的作用是用来创建一个类的不同类型对象,既然这样的话,我们在一个类中使用多种重载的构造方法不就好了吗,为什么要多此一举再创建一个工厂类来创建一个类的不同类型的对象呢?

如果我们不使用工厂类来创建不同类型的对象,那么在创建对象的时候就需要在客户端中显式地选择合适的构造方法并提供对应的参数,这样的话类的具体创建逻辑就暴露了。而使用工厂模式的话,客户端代码只需调用工厂类的接口即可,而无需了解具体的创建逻辑。这样可以将对象的创建与使用代码分离,使得系统更加灵活,可扩展性更强。同时,使用工厂模式还可以避免在客户端代码中暴露对象的创建逻辑,提高了系统的安全性。

在这里插入图片描述
当创建线程池对象的时候,我们只需要调用 Executors 工厂类的对应静态方法,并且传递对应的参数就可以得到不同类型的 ThreadPoolExexutor 实例了,通过这个工厂模式既实现了创建一个类的不同实例的功能,又保证了系统的安全性。

3.4 Executors 创建不同具有不同特性的线程池

在知道什么是工厂模式之后,我们就利用这个工厂类来创建出需要的线程池实例,那么 Executors 工厂类又提供了哪些创建线程池对象的方法呢?它们又分别具有什么特性呢?

newFixedThreadPool() 方法
在这里插入图片描述

在这里插入图片描述

newCachedThreadPool() 方法
在这里插入图片描述
在这里插入图片描述

newScheduledThreadPool() 方法
在这里插入图片描述
在这里插入图片描述

Executors 工厂类还有很多不同的创建线程池对象的方法,这里我就不给大家一一展示出来了,大家如果感兴趣的话,可以去Java帮助文章上去查看。

3.5 ThreadPool 类的构造方法

通过查看源码,我们可以知道,Executors 工厂类创建的线程池对象都是通过传递不同的参数来实例化 ThreadPool 类的,也就是说 ThreadPool 类具有多种构成重载的构造方法,那么来看看这些不同的构造函数的参数分别代表什么吧。
在这里插入图片描述

  • corePoolSize 表示线程池中的核心线程数
  • maximumPoolSize 表示线程池中可含有的最大线程数
  • keepAliveTime 表示当线程池中的线程数量超过核心线程数(corePoolSize)时,多余的空闲线程在终止之前等待新任务的最长时间。
  • TimeUnit unit 用于指定keepAliveTime参数的时间单位。
  • workQueue 表示阻塞队列,可以根据需要设置阻塞队列的类型,如果需要优先级,则可以使用PriorityBlockingQueue;如果不需要优先级且任务的数目是恒定的,则可以使用ArrayBlockingQueue;如果任务的数目不是恒定的,则可以使用LinkedBlockingQueue
  • ThreadFactory 表示工厂类
  • RejectedExecutionHandle handle 表示拒绝策略

这里解决策略是面试中容易考的高频考点,那么这里我们就来详细的说说关于线程池的拒绝策略。

3.6 线程池的拒绝策略

当线程池中容纳的任务数量到达了最大限制之后,如果继续往里面添加任务的话,会出现什么情况呢?Java 中提供了4种拒绝策略。

  1. ThreadPoolExecutor.AbortPolicy 抛出异常
  2. ThreadPoolExecutor.CallerRunsPolicy 新添加的任务由添加任务的线程执行该任务
  3. ThreadPoolExecutor.DiscardOldestPolicy 丢弃掉最旧的未被处理的请求
  4. ThreadPoolExecutor.DiscardPolicy 丢弃掉当前新加的任务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.7 调用 submit 方法添加任务

当创建了适当的线程池对象并且了解了其中创建的细节了之后,我们就需要调用该线程对象的相关方法来执行代码。

使用 submit 方法来添任务。

public class Demo1 {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(4);service.submit(new Runnable() {@Overridepublic void run() {System.out.println("线程1");}});service.submit(new Runnable() {@Overridepublic void run() {System.out.println("线程2");}});service.submit(new Runnable() {@Overridepublic void run() {System.out.println("线程3");}});service.submit(new Runnable() {@Overridepublic void run() {System.out.println("线程3");}});}
}

在这里插入图片描述

4. 自己实现一个线程池

同样的虽然 Java 标准库提供了线程池,但是我们作为初学者如果能够自己实现一个线程池,那么对于我们理解其中的逻辑和细节很有帮助。

class MyThreadPool {//创建一个阻塞队列BlockingDeque<Runnable> queue = new LinkedBlockingDeque<>();//实现submit方法public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}//实现构造方法,类创建的时候就会执行任务public MyThreadPool(int n) {for(int i = 0; i < n; i++) {Thread t = new Thread(() -> {Runnable runnable = null;try {runnable = queue.take();} catch (InterruptedException e) {throw new RuntimeException(e);}runnable.run();});t.start();}}
}

测试

public class Demo2 {public static void main(String[] args) throws InterruptedException {MyThreadPool myThreadPool = new MyThreadPool(4);for(int i = 0; i < 4; i++) {int id = i;myThreadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println("执行线程 " + id);}});}}
}

在这里插入图片描述
由于使用的是阻塞队列,所以当线程池中的任务达到数量限制的时候,如果再添加任务,会进入阻塞等待状态,这是不同于Java标准库提供的四种拒绝策略。

相关文章:

【JavaEE】多线程案例-线程池

文章目录 1. 什么是线程池2. 为什么要使用线程池&#xff08;线程池有什么优点&#xff09;3. 如何使用Java标准库提供的线程池3.1 创建一个线程池对象3.2 什么是工厂模式3.3 为什么要使用工厂模式3.4 Executors 创建不同具有不同特性的线程池3.5 ThreadPool 类的构造方法3.6 线…...

服务器搭建(TCP套接字)-fork版(服务端)

基础版的服务端虽然基本实现了服务器的基本功能&#xff0c;但是如果客户端的并发量比较大的话&#xff0c;服务端的压力和性能就会大打折扣,为了提升服务端的并发性能&#xff0c;可以通过fork子进程的方式&#xff0c;为每一个连接成功的客户端fork一个子进程&#xff0c;这样…...

缺失的第一个正数:高效解法与技术

缺失的第一个正数&#xff1a;高效解法与技术 背景 在计算机编程中&#xff0c;有时候需要寻找一个未排序整数数组中没有出现的最小的正整数。这篇技术博客将详细讨论这个问题&#xff0c;并提供一个时间复杂度为 O(n) 且只使用常数级别额外空间的解决方案。 问题描述 leet…...

常用的辅助网站(持续更新)

标题 一、uni-app方向二、H5方向 一、uni-app方向 1、uni-app官网 地址&#xff1a;https://uniapp.dcloud.net.cn/ 2、香蕉云编 地址&#xff1a;https://www.yunedit.com/ 描述&#xff1a;一般用来配置ios证书或安卓证书、上传ios包至商店 3、uView 地址&#xff1a;http…...

LeetCode 75 - 01 : 最小面积矩形

type pair struct{x, y int }func minAreaRect(points [][]int)int{mp : map[pair]struct{}{}// 将二维数组中的坐标映射到map中for i : range points{mp[pair{points[i][0], points[i][1]}] struct{}{}}// 将结果设置为一个最大值&#xff0c;防止影响求最小值的逻辑res : ma…...

每日一题:请解释什么是闭包(Closure)?并举一个实际的例子来说明。(前端初级)

今天继续在前端初级笔试题中被AI虐&#xff1a; 碱面的答案&#xff0c;问题&#xff1a;初级&#xff0c;回答&#xff1a;初级https://bs.rongapi.cn/1702510598371151872/14我的回答如下&#xff1a; 闭包是指由大括号包裹的一个区域&#xff0c;这个区域代表了一个变量生效…...

广告主必看!NetMarvel五大优势驱动出海App投放增长

App出海走到今天&#xff0c;流量红利早就不存在&#xff0c;摆在广告主面前最棘手的两个问题&#xff0c;一是不起量&#xff0c;二是买量成本太高&#xff0c;得不偿失。 如何在确保出海应用用户规模有所增长的同时&#xff0c;也保证整体ROI处在较高水平&#xff1f;NetMar…...

数据结构与算法之复杂度

时间复杂度 1.抓大头 2.常数用o(1),低阶函数也用o(1)代替&#xff08;直接去掉&#xff09; 3.取最坏情况 对数相关写法的规定...

ATECLOUD电源测试软件平台如何测试电源纹波?

电源纹波是影响电源稳定性的重要因素&#xff0c;过大的纹波会导致电源模块的工作效率降低&#xff0c;可能使电源模块直接损坏。使用ATECLOUD碘盐测试软件平台对纹波进行测试&#xff0c;检测其工作情况&#xff0c;以确保其稳定性和性能。 电源纹波的产生 电源的纹波通俗的来…...

数据结构与算法:排序算法(2)

目录 堆排序 使用步骤 代码实现 计数排序 适用范围 过程 代码实现 排序优化 桶排序 工作原理 代码实现 堆排序 二叉堆的特性&#xff1a; 1. 最大堆的堆顶是整个堆中的最大元素 2. 最小堆的堆顶是整个堆中的最小元素 以最大堆为例&#xff0c;如果删除一个最大堆的…...

1_图神经网络GNN基础知识学习

文章目录 安装PyTorch Geometric安装工具包 在KarateClub数据集上使用图卷积网络 (GCN) 进行节点分类两个画图函数Graph Neural Networks数据集&#xff1a;Zacharys karate club network.PyTorch Geometric数据集介绍 edge_index使用networkx可视化展示 Graph Neural Networks…...

瑞芯微:基于RK3568的ocr识别

光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;是指对文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的过程。亦即将图像中的文字进行识别&#xff0c;并以文本的形式返回。OCR的应用场景 卡片证件识别类&#xff1a;大陆、港澳…...

C++真的是 C加加

&#x1f4dd;个人主页&#xff1a;夏目浅石. &#x1f4cc;博客专栏&#xff1a;C的故事 &#x1f3e0;学习社区&#xff1a;夏目友人帐. 文章目录 前言Ⅰ. 函数重载0x00 重载规则0x01 函数重载的原理名字修饰 Ⅱ. 引用0x00 引用的概念0x01 引用和指针区分0x03 引用的本质0x04…...

java学习--day5 (java中的方法、break/continue关键字)

文章目录 day4作业今天的内容1.方法【重点】1.1为什么要有方法1.2其实已经见过方法1.3定义方法的语法格式1.3.1无参无返回值的方法1.3.2有参无返回值的方法1.3.3无参有返回值的方法1.3.4有参有返回值的方法 2.break和continue关键字2.1break;2.2continue; 3.案例关于方法的练习…...

MFC主框架和视类PreCreateWindow()函数学习

在VC生成的单文档应用程序中&#xff0c;主框架类和视类均具有PreCreateWindow函数&#xff1b; 从名字可知&#xff0c;可在此函数中添加一些代码&#xff0c;来控制窗口显示后的效果&#xff1b; 并且它有注释说明&#xff0c; Modify the Window class or styles here by…...

for forin forof forEach map区别

一、总结 相同点&#xff1a;都是串行遍历。不同点&#xff1a; 二、for of循环 设计目的&#xff1a;遍历所有数据结构的统一方法。原理&#xff1a;会调用数据结构的Symbol.iterator方法。 只要数据结构定义了Symbol.iterator属性&#xff0c;就能用for of遍历它的成员。…...

特殊时间(蓝桥杯)

特殊时间 问题描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 2022年2月22日22:20 是一个很有意义的时间, 年份为 2022 , 由 3 个 2 和 1 个 0 组成, 如果将月和日写成 4 位, 为 0222 , 也是由 3 个 2 和 1 个 0 组 成…...

VUE路由与nodeJS环境搭建

VUE路由 Vue路由是Vue.js提供的路由管理工具&#xff0c;它允许我们在应用程序中实现页面之间的导航&#xff0c;从而使单页面应用程序的开发更加方便。通过Vue路由&#xff0c;我们可以轻松地创建和管理多个视图&#xff0c;并在这些视图之间导航。 Vue路由使用HTML5的Histo…...

抗锯齿的线

抗锯齿的线 右下角的时候h是0,到顶部 h是1&#xff0c;然后中间y相距4个像素&#xff0c;那dy就是0.25 如果让h abs(fract(h - 0.5) - 0.5) 中间一行0.5&#xff0c;第一行 第三行都是0.25&#xff0c;两端都是0 根据插值来看 这里是 如果用h/dy 那么第一行以上&#xff0…...

如何使用高压放大器驱动高容性负载

使用高压放大器驱动高容性负载是一个具有挑战性的任务&#xff0c;需要仔细考虑电路设计和操作技巧。下面西安安泰Aigtek将为您介绍一些关于如何使用高压放大器驱动高容性负载的方法和注意事项。 首先&#xff0c;让我们了解一下高容性负载。高容性负载通常指电容值较大的负载元…...

kubernetes集群证书过期启动失败问题解决方法

1、问题现象 执行kubectl命令异常报告 [rootk8s-master1 ~]# kubectl get node The connection to the server 192.168.227.131:6443 was refused - did you specify the right host or port? [rootk8s-master1 ~]# 查看etcd的日志&#xff0c;报错信息如下 {"level&…...

nvm使用的注意事项和常用命令。

nvm官网下载地址&#xff1a;nvm文档手册 - nvm是一个nodejs版本管理工具 - nvm中文网 (uihtm.com) 参考网址&#xff1a;(14 封私信 / 80 条消息) 如何通过 nvm 安装多版本 nodejs&#xff1f;npm 安装失败了怎么办&#xff1f; - 知乎 (zhihu.com) nvm目录下&#xff0c;修…...

代码大全阅读随笔(七)

循环控制 循环控制会出现什么样的错误&#xff0c;任何一种答案都可以归结到下面所说的问题之一&#xff1a;忽略或者错误的对循环执行初始化&#xff0c;忽略了对累加变量或者其他与循环有关变量执行初始化&#xff0c;不正确的嵌套&#xff0c;不正确的循环终止&#xff0c;忽…...

用户与权限管理

文章目录 用户与权限管理1. 用户管理1.1 MYSQL用户1.2 登录MySQL服务器1.3 创建用户1.4 修改用户1.5 删除用户1.6 修改密码1. 修改当前用户密码2. 修改其他用户密码 1.7 MYSQL8密码管理 2. 权限管理2.1 权限列表2.2 授予权限的原则2.3 授予权限2.4 查看权限2.5 收回权限 3. 权限…...

mysql集群使用nginx配置负载均衡

参考链接&#xff1a;https://mu-sl.com//archives/mysql%E9%9B%86%E7%BE%A4%E4%BD%BF%E7%94%A8nginx%E9%85%8D%E7%BD%AE%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1 配置文件nginx_tcp.conf 示例 load_module modules/ngx_stream_module.so;stream{upstream tcpssh{hash $remote_…...

蓝桥杯每日一题2023.9.21

蓝桥杯2021年第十二届省赛真题-异或数列 - C语言网 (dotcpp.com) 题目描述 Alice 和 Bob 正在玩一个异或数列的游戏。初始时&#xff0c;Alice 和 Bob 分别有一个整数 a 和 b&#xff0c;有一个给定的长度为 n 的公共数列 X1, X2, , Xn。 Alice 和 Bob 轮流操作&#xff0…...

知识联合——函数指针数组

前言&#xff1a;小伙伴们又见面啦&#xff0c;今天我们来讲解一个将函数&#xff0c;指针&#xff0c;数组这三个C语言大将整合在一起的知识——函数指针数组。同时来告诉小伙伴们我们上一篇文章的伏笔——函数指针的具体用法。 目录 一.什么是函数指针数组 二.函数指针数组…...

【Nginx26】Nginx学习:日志与镜像流量复制

Nginx学习&#xff1a;日志与镜像流量复制 总算到了日志模块&#xff0c;其实这个模块的指令之前我们就用过了&#xff0c;而且也是是非常常见的指令。相信这一块的学习大家应该不会有什么难度。另一个则是镜像功能&#xff0c;这个估计用过的同学就比较少了&#xff0c;不过也…...

Stability AI发布基于稳定扩散的音频生成模型Stable Audio

近日Stability AI推出了一款名为Stable Audio的尖端生成模型&#xff0c;该模型可以根据用户提供的文本提示来创建音乐。在NVIDIA A100 GPU上Stable Audio可以在一秒钟内以44.1 kHz的采样率产生95秒的立体声音频&#xff0c;与原始录音相比&#xff0c;该模型处理时间的大幅减少…...

华为OD机试 - 计算面积 - 逻辑分析(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…...

北京网站建设开发专业公司/百度站内搜索代码

在这个Java Challenger中&#xff0c;您将学习equals()和hashcode()结合如何使Java程序中的对象比较高效而又容易。 简而言之&#xff0c;这些方法可以共同验证两个对象是否具有相同的值。 如果没有equals()和hashcode()我们将不得不创建非常大的“ if ”比较&#xff0c;以比…...

定制开发电商网站建设多少钱/手机百度高级搜索入口在哪里

目录 文章目录目录RSS 多队列网卡RSS 技术实现原理RSS FilterRSS HASH硬中断信号绑定ethtool 操作指令RSS 多队列网卡 在以往&#xff0c;一张 NIC 只具有一个 Rx Queue&#xff0c;对应一个 CPU Core 来进行收包处理。在多核时代&#xff0c;为了充分利用 Multi-CPU Cores&am…...

自己做网站哪家好/免费b站推广短视频

文章目录文件表达式整数变量表达式字符串变量表达式s​h​e​l​l​中​条​件​判​断​i​f​中​的​-​z​到​-​d​的​意​思文件表达式 if [ -f file ] 如果文件存在 if [ -d … ] 如果目录存在 if [ -s file ] 如果文件存在且非空 if [ -r file ] 如果文件存在且可读…...

预约营销型网站建设专家/成人短期就业培训班

敢在今年提裸辞的人&#xff0c;都是勇士。 这是最近笔者在就业话题下看到得最多的一句话。几年前&#xff0c;逃离北上广深的话题火了&#xff0c;也随之而来带起了一股裸辞的风潮。“世界这么大&#xff0c;我想去看看。”成为了年轻人追求自由的目标。 而今年&#xff0c;…...

京东云免费建wordpress/内蒙古seo

一、面向对象编程 ​ 面向过程编程&#xff1a;关注于解决问题的方法、步骤。 ​ 面向对象编程&#xff1a;关注于谁能解决问题(类)&#xff0c;以及解决问题需要的数据(成员变量)&#xff0c;以及解决问题需要的技能(成员函数)。 ​ 抽象&#xff1a;想象出一个能解决问题的…...

wordpress oss静态/安装百度一下

文章目录前言一、收货地址功能实现二、效果前言 在电商系统中&#xff0c;收货地址是必不可少的功能&#xff0c;没有收货地址用户在下单就没法收到货&#xff0c;而且一个用户会有多个收货地址&#xff0c;比如寄给自己&#xff0c;或者寄给别人。一搬在收货地址选择中会有个…...