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

【JavaEE】——线程池大总结

8e19eee2be5648b78d93fbff2488137b.png

阿华代码,不是逆风,就是我疯,

你们的点赞收藏是我前进最大的动力!!希望本文内容能够帮助到你!

目录

 

引入:问题引入

一:解决方案

1:方案一——协程/纤程

(1)本质

2:方案二——线程池

(1)本质

(2)优缺点

(3)解释高效的原因

二:ThreadPoolExecutor(标准库线程池)

1:Java库中找

2:构造方法

(1)核心线程数

(2)最大线程数

(3)保持存活时间

(4)时间单位

(5)工作任务

(6)线程工厂

①工厂模式

(7)拒绝策略(面试高频)

①中止策略

②甩锅策略

③喜新厌旧

④忠贞不渝

三:Executors(工厂类)

1:.newFixedThreadPool(可以设定固定线程数目)

2:submit添加任务

​编辑3:线程池中线程数量问题

(1)前引

(2)线程任务的分类

①CPU密集型任务

②IO密集型任务

(3)分情况讨论

四:通过代码实现简单的线程池

1:思路

2:代码示例


 

引入:问题引入

在之前的学习中,我们了解到,为了降低频繁创建和销毁进程所带来的巨大开销,我们引入了轻量级进程的概念(线程)

现在若线程的数量进一步提升,那么线程的频繁创建和销毁所带来的资源消耗,我们也不能忽视了

所以我们进行优化,引入了“池”的概念:这里有许多种类的池,线程池,数据库连接池,进程池......(提前把需要用到的对象准备好,用完的 对象也不要直接扔掉,放到池子中以便下次使用)

一:解决方案

1:方案一——协程/纤程

注:可以理解为轻量级线程

(1)本质

通过用户态代码进行调度,不靠系统内核的调度器调度(节省了调度的开销)

注:在java21中“虚拟线程”就是这个意思。

       在用户代码中,协程是基于线程进行封装的。

       go是比较早支持协程的,因为语法简单就火了

2:方案二——线程池

(1)本质

提前创建好线程,需要用的时候直接从池子里拿出来用,用完了也不要释放而是返还回池子中。

(2)优缺点

①优点:节省了创建和销毁线程带来的资源消耗,更高效

②缺点:占用了内存空间

(3)解释高效的原因

从线程池里获取线程,是在用户态代码中进行调度,是可控的,高效的

从操作系统中获取线程,是在系统内核中进行完成的,不可控,低效。

d9d7e3ce0b0a4962bbfed46e54794091.png

二:ThreadPoolExecutor(标准库线程池)

1:Java库中找

注:打开网站Overview (Java Platform SE 8 ),找到对应的包和class类

0bd458fa4e224b228cdd4015390c97cc.png6e6683c97721479fafbf61c0300326da.png

2:构造方法

6e2ebb9fc3604278acb46a94525d104b.png

我们直接看带有7个参数的构造方法

(1)核心线程数

int corePoolSize

core(核心)pool(池)siz(大小)

 

(2)最大线程数

int maximumPoolSize

核心线程可以理解为公司的正式员工,不能轻易裁掉;

普通线程可以理解为公司的实习生,裁掉比较容易

最大线程数 =  核心线程数 +普通线程数

(3)保持存活时间

long keepAliveTime

(4)时间单位

TimeUnit unit

单位:s,min,hour.......

普通线程能空闲的最大时间,超过空闲时间限制,就会被移除线程池

还是用上述例子举例,实习生不能说开就开,假定摸鱼时间限制为1个小时,只要实习生摸鱼的时间小于1个小时就不会被开,超过就被开

(5)工作任务

BlockingQueue<Runnable>  workQueue

与定时器(上篇文章)相似,线程池可以持有多个任务

Runnable用来描述任务的主体

<>也可以写PriorityQueue优先级队列

(6)线程工厂

ThreadFactory threadFactory

①工厂模式

通过(“工厂类”)类里面的(不一定是静态的)方法,对方法内部的new对象进行构造,完成对象的初始化(相当于,给构造方法外面在套上一层方法——套娃“封装”)

1026669ae539467eba5db3feddc92d69.png

56d76f658d634176af0e1525b9c47803.png

 

(7)拒绝策略(面试高频)

RejectedExecutionHandler handler——

execution(执行)handler(操作者)

问题:试想,线程池中有一个阻塞队列,存放的线程数目已经达到最大荣达,这个时候还往里面存放,那么线程池会怎么办?

d00ce6ae559744cebd67b9a6568ccf83.png

①中止策略

.AbortPolicy ——

如果硬要在加新任务的话,线程池:我吃柠檬,lz新旧任务都不干了,抛出异常

651361d0a53a442aae9e3ae6feaec96d.png

②甩锅策略

.CallerRunsPolicy——

线程池:让交代给我这个任务的人自己完成这个线程,我才不干

③喜新厌旧

.DiscardOldestPolicy——

discard(丢弃)

线程池抛弃池中呆的最久最老的一个线程,迎接新欢(喜新厌旧)

④忠贞不渝

.DiscardPolicy——

丢弃要新添加的任务,继续我行我素执行线程池中本来就有的任务

三:Executors(工厂类)

因为ThreadPoolExecutor使用起来较为复杂,所以标准库中就封装了一下,提供了Executors这个版本(工厂类,在内部把ThreadPoolExecutor创建好了,并且设置了不同的参数)

1:.newFixedThreadPool(可以设定固定线程数目)

c4ea4d8220f54f039b6a7b0ccf4082f6.png

2:submit添加任务

package thread;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadDemon34 {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(4);service.submit(new Runnable(){@Overridepublic void run() {System.out.println("执行线程池中第一个任务");}});}
}

edd48773c8d94b3980f8bae858716683.png

返回值类型点进去

ac27eadab28f421b841c96ae04be4c54.png3:线程池中线程数量问题

(1)前引

我们知道,线程的运行效率,跟cpu的逻辑核心数直接相关,假设cpu的逻辑核心数为N,那线程的数量该是多少合适(2N?1.5N?N?..........)

(2)线程任务的分类

①CPU密集型任务

线程大部分时间都在CPU上运行,计算

②IO密集型任务

大部分时间都在等待IO(input,output)。例如:Scanner读取用户的输入

(3)分情况讨论

到底在线程池中添加多少线程数量合适呢?

如果线程多为CPU类型的,那线程数目尽量不要超过N

如果线程多为IO类型的,那线程数目就可以远远超过N

但是具体开发肯定是需要我们多次测试,通过观察系统资源消耗,来找出最合适的添加数目的。

四:通过代码实现简单的线程池

1:思路

大逻辑其实就是,把创建的任务提交上去,再把任务取出来,在run执行就可以了就是这么简单

我们用到的IDEA自带的顺序表,阻塞队列BlockingQueue都其实是一个工具罢了~~

2:代码示例

package thread;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-27* Time: 16:48*/class MyThreadPoolExecutor{//2:创建一个顺序表来接收创建的线程private List<Thread> threadList = new ArrayList<>();//4创建一个容量合适的阻塞队列private BlockingQueue<Runnable> queue = new ArrayBlockingQueue(1000);//1:通过一个循环,n的值,来控制产生的线程的数量public MyThreadPoolExecutor(int n){for (int i = 0; i < n; i++) {Thread t = new Thread(()->{//6:把要做的任务从任务队列中不停地取出来,并且执行while(true){try {//带有阻塞的take取出元素Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();//3:threadList.add(t);}}//5:提交runnable到队列里面去public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}
}
public class ThreadDemon35 {//大逻辑其实就是,把创建的任务提交上去,再把任务取出来,在run执行就可以了就是这么简单public static void main(String[] args) throws InterruptedException {MyThreadPoolExecutor executor = new MyThreadPoolExecutor(4);for (int i = 0 ; i < 1000 ; i++){//变量捕获int n = i;executor.submit(new Runnable() {@Overridepublic void run() {System.out.println("执行任务:" + n + "  " + "当前线程为:" + Thread.currentThread().getName());}});}}
}

2a747122a79e46c58058b5cb54441881.png

 

相关文章:

  • 上海建站提升在线曝光率的关键
  • 记Flink SQL 将数据写入 MySQL时的一个优化策略
  • 宝塔面板部署雷池社区版教程
  • MySql在更新操作时引入“两阶段提交”的必要性
  • 数据结构及基本算法
  • 《深度学习》卷积神经网络CNN 实现手写数字识别
  • 一次阿里云ECS免费试用实践
  • lime使用记录
  • Nginx配置及部署前端项目,安排!
  • Rce脚本自动化amp;批量
  • TDengine 签约青山钢铁,实现冶金全流程质量管控智能化
  • vue.js 原生js app端实现图片旋转、放大、缩小、拖拽
  • 服务器的地址如何伪装起来
  • PWM基础与信号控制
  • python 图像绘制问题: 使用turtle库绘制蟒蛇
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • java2019面试题北京
  • JSDuck 与 AngularJS 融合技巧
  • JS变量作用域
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • LeetCode18.四数之和 JavaScript
  • SpiderData 2019年2月16日 DApp数据排行榜
  • SpingCloudBus整合RabbitMQ
  • Swift 中的尾递归和蹦床
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 机器学习学习笔记一
  • 记录一下第一次使用npm
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • ​【数据结构与算法】冒泡排序:简单易懂的排序算法解析
  • ​ssh免密码登录设置及问题总结
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • (1)Hilt的基本概念和使用
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (笔记)M1使用hombrew安装qemu
  • (第二周)效能测试
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (计算机网络)物理层
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (实战篇)如何缓存数据
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)基于IDEA的JAVA基础10
  • *** 2003
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .Net Memory Profiler的使用举例
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .net 简单实现MD5
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET大文件上传知识整理