当前位置: 首页 > 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…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...