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

自定义线程池实现(一)

预期目标

1.实现一个相对完备的线程池
2.自定义拒绝策略(下一节)

线程池的基本参数

1.核心线程数
2.超时时间
3.拒绝策略(在下一篇中添加)
4.工作队列
5.任务队列
在这里插入图片描述

工作机制

当添加一个任务到线程池中时,线程池会判断工作线程数量是否小于核心线程数,若小于创建工作线程,执行任务;反之将其添加到任务队列,若是当前任务队列已经满了,可以执行拒绝策略(拒绝策略有很多种,例如死等[会阻塞main线程],放弃任务,抛出异常等等)

工作线程执行过程

工作线程会先将手头上的任务干完,然后到工作队列当中取,如果工作队列中还有任务,取出来继续执行…(周而复始)
但是有可能在一段时间内,工作队列中没任务执行,这个时候我们可以选择让它死等,或者超出指定时间之后自己销毁。

了解这些之后,正式开始coding…

1.构建一个阻塞队列

在前面博客中已经实现过了,需要锁,两个条件变量[生产者,消费者],普通队列这三个参数。

@Slf4j
class BlockQueue<T> {//1.任务队列private Deque<T> tDeque = new ArrayDeque<>();//2.锁private ReentrantLock lock = new ReentrantLock();//3.两个条件变量(生产者消费者)private Condition notEmpty;private Condition notFull;private int capacity;public BlockQueue(int capacity) {this.notEmpty = lock.newCondition();this.notFull = lock.newCondition();this.capacity = capacity;}//带超时的阻塞获取public T poll(long timeout, TimeUnit timeUnit) {lock.lock();try {//将timeout转换long nanos = timeUnit.toNanos(timeout);while (tDeque.isEmpty()) {try {//返回的是剩余的时间if (nanos <= 0) return null;nanos = notEmpty.awaitNanos(nanos);} catch (InterruptedException e) {log.error("error{}",e.getMessage());}}notFull.signal();return tDeque.removeFirst();} finally {lock.unlock();}}//消费者public T take() {lock.lock();try {while (tDeque.isEmpty()) {try {notEmpty.await();} catch (InterruptedException e) {log.error("error{}",e.getMessage());}}notFull.signal();return tDeque.removeFirst();//消费对头} finally {lock.unlock();}}//阻塞添加//生产者public void put(T ele) {lock.lock();try {while (tDeque.size() == capacity) {try {log.info("等待加入任务队列......");notFull.await();} catch (InterruptedException e) {log.error("error{}",e.getMessage());}}log.info("已加入任务队列");tDeque.addLast(ele);notEmpty.signal();} finally {lock.unlock();}}//非阻塞式添加//即使失败也不会阻塞住主线程public boolean offer(T ele, long timeout, TimeUnit timeUnit){lock.lock();try {long nanosTime = timeUnit.toNanos(timeout);while (tDeque.size() == capacity) {try {if (nanosTime <= 0) return false;nanosTime = notFull.awaitNanos(nanosTime);} catch (InterruptedException e) {log.error("error{}",e.getMessage());}}log.info("已加入任务队列");tDeque.addLast(ele);notEmpty.signal();return true;} finally {lock.unlock();}}//获取大小public int size() {lock.lock();try {return tDeque.size();} finally {lock.unlock();}}
}

2.写线程池

@Slf4j
class ThreadPool {//任务队列private BlockQueue<Runnable> taskQueue;//线程集合 我们需要对线程做一个包装private HashSet<Worker> workers = new HashSet<>();//核心线程数量private long coreSize;//超时时间private long timeout;//时间单位private TimeUnit timeUnit;//自定义拒绝策略//private RejectPolicy rejectPolicy;public ThreadPool(int queueCapacity,long coreSize,long timeout,TimeUnit timeUnit){taskQueue = new BlockQueue<>(queueCapacity);this.coreSize = coreSize;this.timeout = timeout;this.timeUnit = timeUnit;}//执行任务public void execute(Runnable task){//当任务数量尚未超过coreSizesynchronized (workers){if (workers.size() < coreSize){log.info("创建工作线程{}",task);Worker worker = new Worker(task);workers.add(worker);worker.start();}else{log.info("加入到任务队列{}",task);//有可能会阻塞在这里 进而将主线程阻塞掉taskQueue.put(task);//这里会有很多种策略自定义策略//1.死等//2.带超时等待//3.让调用者放弃任务执行//4.让调用者抛出异常//5.让调用者自己执行任务//策略模式:操作抽象成接口实现代码是传过来不会写死}}}class Worker extends Thread{private Runnable task;public Worker(Runnable task){this.task = task;}@Overridepublic void run() {while (task != null || (task = taskQueue.poll(timeout,timeUnit)) != null){try {log.info("正在执行...{}",task);//执行任务task.run();}catch (Exception e){System.out.println(e.getMessage());}finally {//不要忘记这一步task = null;}}synchronized (workers){log.info("worker被移除{}",this);workers.remove(this);}}}
}

测试:

[main] INFO com.define.ThreadPool - 创建工作线程com.define.TestPool$$Lambda$1/1880587981@65b3120a
[main] INFO com.define.ThreadPool - 创建工作线程com.define.TestPool$$Lambda$1/1880587981@4783da3f
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@49097b5d
[Thread-0] INFO com.define.ThreadPool - 正在执行...com.define.TestPool$$Lambda$1/1880587981@65b3120a
[main] INFO com.define.BlockQueue - 已加入任务队列
[Thread-1] INFO com.define.ThreadPool - 正在执行...com.define.TestPool$$Lambda$1/1880587981@4783da3f
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@6e2c634b
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@37a71e93
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@7e6cbb7a
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@7c3df479
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@7106e68e
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@7eda2dbb
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@6576fe71
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@76fb509a
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@300ffa5d
[main] INFO com.define.BlockQueue - 已加入任务队列
[main] INFO com.define.ThreadPool - 加入到任务队列com.define.TestPool$$Lambda$1/1880587981@1f17ae12
[main] INFO com.define.BlockQueue - 等待加入任务队列......

测试没什么问题,但是能发现如果当前工作线程都是busy,并且任务队列也满了,当执行put的时候,就会阻塞在这里,put阻塞—>execute阻塞---->main线程阻塞,当然阻塞也是一种方式那如果不想让它阻塞,比如我添加不进去想让他直接丢弃或者抛出异常应该怎么办,那就需要自定义一套拒绝策略,下一节继续。

相关文章:

自定义线程池实现(一)

预期目标 1.实现一个相对完备的线程池 2.自定义拒绝策略&#xff08;下一节&#xff09; 线程池的基本参数 1.核心线程数 2.超时时间 3.拒绝策略&#xff08;在下一篇中添加&#xff09; 4.工作队列 5.任务队列 工作机制 当添加一个任务到线程池中时&#xff0c;线程池会…...

计算机毕业设计选题推荐-零食批发商仓库管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…...

基于springboot+vue+uniapp的校园快递平台小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…...

这两个大龄程序员,打算搞垮一个世界软件巨头!

大家都知道&#xff0c;Adobe是多媒体和数字内容创作者的绝对王者&#xff0c;它的旗下有众多大家耳熟能详的软件&#xff1a;Photoshop、Illustrator、Premiere Pro、After Effects、InDegign、Acrobat、Animate等等。 这些软件使用门槛很高&#xff0c;价格昂贵&#xff0c;安…...

LabVIEW放大器自动测量系统

开发了一个基于LabVIEW平台的多路前置放大器自动测量系统的开发与实施。该系统集成了硬件控制与软件编程&#xff0c;能够实现放大器各项性能指标的快速自动测量&#xff0c;有效提高了测试的精确性和效率。系统设计采用了虚拟仪器技术&#xff0c;结合了先进的测量与控制策略&…...

全面整理人工智能(AI)学习路线图及资源推荐

在人工智能&#xff08;AI&#xff09;飞速发展的今天&#xff0c;掌握AI技术已经成为了许多高校研究者和职场人士的必备技能。从深度学习到强化学习&#xff0c;从大模型训练到实际应用&#xff0c;AI技术的广度和深度不断拓展。作为一名AI学习者&#xff0c;面对浩瀚的知识海…...

react antd upload custom request处理多个文件上传

react antd upload custom request处理多个文件上传的问题 背景&#xff1a;第一次请求需要请求后端返回aws 一个link&#xff0c;再往link push文件&#xff0c;再调用另一个接口告诉后端已经上传成功&#xff0c;拿到返回值。 再把返回值传给业务api... 多文件上传一直是循环…...

ALB快速实现IPv4服务的负载均衡

阿里云应用型负载均衡ALB支持HTTP、HTTPS和QUIC协议&#xff0c;专门面向网络应用层&#xff0c;提供强大的业务处理能力。 为了实现IPv4服务的负载均衡&#xff0c;需要快速创建一个ALB实例&#xff0c;并将来自客户端的访问请求转发至后端服务器。 操作流程 第一步&#x…...

【LLM】-12-部署Langchain-Chatchat-0.3.x版本

目录 1、0.3与0.2的功能对比 2、0.3.x支持多种部署方式 2.3、源码安装 2.3.1、项目源码下载 2.3.2、创建conda环境 2.3.3、安装poetry 2.3.4、安装依赖库 2.3.5、项目初始化 2.3.6、配置文件 2.3.7、初始化知识库 2.3.7、启动服务 2.3.8、配置说明 2.3.8.1、basic_…...

优化网络接收缓存减少数据丢包

视频领域&#xff0c;网络udp数据丢包会引起视频解码花屏。 1、修订单个socket的缓冲区大小&#xff1a;通过setsockopt使用SO_RCVBUF来设置接收缓冲区&#xff0c;该参数在设置的时候不会与rmem_max进行对比校验&#xff0c;但是如果设置的大小超过rmem_max的话&#xff0c;则…...

数据透视——判别分析

文章目录 判别分析简介常用的判别分析方法距离判别贝叶斯判别线性判别分析&#xff08;LDA&#xff09;支持向量机&#xff08;SVM&#xff09;总结 补充 在数据科学的丰富领域中&#xff0c;判别分析扮演着至关重要的角色。它是一种统计方法&#xff0c;用于预测样本数据的类别…...

书生大模型学习笔记 - 连接云端开发机

申请InternStudio开发机&#xff1a; 这里进去报名参加实战营即可获取 书生大模型实战营 InternStudio平台 创建开发机 SSH连接开发机&#xff1a; SSH免密码登录 本地创建SSH密钥 ssh-keygen -t rsa打开以下文件获取公钥 ~/.ssh/id_rsa.pub去InternStudio添加公钥 …...

Python操作符的重载

目录 1、操作符重载的基本概念1.1、常用的操作符重载方法1.1.1、算术操作符1.1.2、比较操作符1.1.3、比其他操作符 1.2、例子 2、应用场景2.1、增强代码的可读性2.2、 实现类的数学运算2.3、支持自定义的数据结构2.4、简化 API 设计2.5、实现链式操作和流式接口 3、总结 Python…...

redis面试(三)Hash数据结构

HASH 哈希&#xff0c;在redis底层实现的时候&#xff0c;数据的结构叫做dict 这个Dict就是一个用于维护key和value映射关系的数据结构&#xff0c;与很多语言中的Map类型相似。 本质上也是一个数组链表的形式存在&#xff0c;不同的点在于&#xff0c;每个dict中是可以存在…...

Java基础语法

注释 注释就是在程序指定位置添加的说明性信息 简单理解&#xff0c;就是对代码的一种解释 注释有三种&#xff1a; 单行注释 格式&#xff1a;//注释信息 多行注释 格式&#xff1a;/*注释信息*/ 文档注释 格式&#xff1a;/**注释信息*/ 注释的注意事项…...

Qt | QChart+QChartView+QLineSeries(折线图)+QBarSeries(柱状图)实战

点击上方"蓝字"关注我们 01、QLineSeries QLineSeries 是 Qt 中的一个类,用于在图表中表示一系列的数据点。它继承自 QAbstractSeries 类,提供了绘制折线图所需的基本功能。 常用的方法包括 append(x, y):向序列中添加一个新的数据点,其中 x 和 y 分别表示横坐…...

公布一批脸书爬虫(facebook)IP地址,真实采集数据

一、数据来源&#xff1a; 1、这批脸书爬虫&#xff08;facebook&#xff09;IP来源于尚贤达猎头公司网站采集数据&#xff1b; ​ 2、数据采集时间段&#xff1a;2023年10月-2024年7月&#xff1b; 3、判断标准&#xff1a;主要根据用户代理是否包含“facebook”和IP核实。…...

Package.Json 参数配置理解用途

"dev": "SET NODE_OPTIONS--openssl-legacy-provider & vue-cli-service serve --open" 这行命令首先设置环境变量NODE_OPTIONS&#xff0c;添加了--openssl-legacy-provider标志。这个标志用于解决某些情况下Node.js在Windows系统上使用OpenSSL时可能…...

k3:增加触发器,当外协单和报料单新增时,更新生产任务单的“说明”栏

外协单新增时 CREATE TRIGGER [dbo].[t_BOS257800018Entry2_update]ON [dbo].[t_BOS257800018Entry2]AFTER insert AS BEGINSET NOCOUNT ON; ------实现当外协时&#xff0c;生产任务单的说明有标识&#xff08;240731 BY WK&#xff09; declare fid_souce as int; declare…...

神奇海洋养鱼小程序游戏广告联盟流量主休闲小游戏源码

在海洋养鱼小程序中&#xff0c;饲料、任务系统、系统操作日志、签到、看广告、完成喂养、每日签到、系统公告、积分商城、界面设计、拼手气大转盘抽奖以及我的好友等功能共同构建了一个丰富而互动的游戏体验。以下是对这些功能的进一步扩展介绍&#xff1a; 饲料 任务奖励&a…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...