简易线程池的实现

Worker的实现 

总体来说我们首先需要实现一个Worker线程类,让他的线程实例拿取任务然后执行任务

//worker主要是从jobs中拿工作,拿不到等,拿到了执行。class Worker implements Runnable{private volatile boolean running = true;@Overridepublic void run() {while (running){Job job = null;synchronized (jobs){while (jobs.isEmpty()){try{jobs.wait();} catch (Exception e){Thread.currentThread().interrupt();return;}}job = jobs.removeFirst();}if (job != null){job.run();}}}public void shutdown(){running = false;}}

由此我们引出了,需要一个集合来保存worker。

private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());

同时worker需要拿取任务,任务需要保存在一个队列中,所以引出来了jobs队列。

private final LinkedList<Job> jobs =new LinkedList<>();

线程池的初始化

前提工作准备好了,我们可以开始去实现一个简易的线程池。

初始化就免不了要提起那设定好初始化的数值。

private static final int DEFAULT_WORKER_NUMBERS = 5;private  int workerNum = DEFAULT_WORKER_NUMBERS;private static final int MAX_WORKER_NUMBERS = 10;private static final int MIN_WORKER_NUMBERS = 1;

初始工人为5个,对应的就是线程池中的核心线程数为5.

wokerNum用来即时记录工人数,也就是线程池中存活的线程数。

并且限制了最大工人数为10,最少工人数为1。对应的是最大线程数为10,最少线程数为1。

接下来就可以执行初始化了。

public ThreadExcutor(){InitialWorkers(DEFAULT_WORKER_NUMBERS);}//将worker放入wokers集合中,然后开始让worker线程执行。private void InitialWorkers(int num){for (int i = 0; i < num; i++) {Worker worker = new Worker();workers.add(worker);Thread thread = new Thread(worker,"ThreadPool-Worker-"+ i);thread.start();}}//判断num是否在最大和最少工人范围之间,在的话将工人数量赋值num,不在的话num大于max就复制max,小于max就赋值minpublic ThreadExcutor(int num){this.workerNum = num > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS : Math.max(num, MIN_WORKER_NUMBERS);InitialWorkers(workerNum);}

如果我们调用构造方法时,没有传入参数,他就直接默认生成5个工人,并将它依次加入工人集合中,并开启这个工人线程。

如果我们调用传入参数的方法,就需要判断传入的参数是否在max和min之间,如果在就赋值给workerNum进行记录,然后初始化相应的工人线程。如果不在就考虑大于max就初始化max的数量,如果小于min就初始化min数量。

线程池的五大基础方法实现

以下四种操作都会涉及到

执行方法

言简意赅就是将job放入jobs队列中,然后唤醒jobs队列。

//如果工作不为空,就将工作放入工作队列中,然后唤醒工作队列public void execute(Job job){if (job != null){synchronized (jobs){jobs.addLast(job);jobs.notify();}}}

添加工人(添加线程)

先判断是否超出最大工人数,超出了的话,强制初始化剩下的工人数。最后别忘了workerNum的即时记录。

//这里初始化时对jobs有操作,所以也对jobs进行加锁。添加工人时需要判断加上原来的工人是否超过了最大的工人数,//如果超过了就将num赋值成不超过最大工人的最大数量,然后去用num数初始化,并且将工人数更新成最新。public void addWorks(int num){synchronized (jobs){if (num + workerNum > MAX_WORKER_NUMBERS){num = MAX_WORKER_NUMBERS - workerNum;}InitialWorkers(num);workerNum += num;}}

移除工人(删除工作线程)

这个就是不断地从工人集合中取出工人,然后将他们shutdown掉。别忘了workerNum的即时记录。

//先检查删除数是否在工人数之内,不在就抛出超出范围的异常。然后在工人集合中不断地取工人,然后进行shutdown,最后workerNum更新成剩下的工人数。public void removeWorkers(int num){synchronized (jobs){if(num >= workerNum){throw new IllegalArgumentException("超出范围");}int count = 0;while (count < num){Worker worker = workers.get(count);if (workers.remove(worker)){worker.shutdown();count++;}}workerNum -= count;}}

获取工作数

//获取工作数public int getJobSize(){return jobs.size();}

停止工人线程

对工人集合进行遍历,逐一调用shutdown方法。

 //遍历工人集合,一个一个关闭public void shutdown(){for (Worker worker : workers) {worker.shutdown();}}

总结

这样一个建议的线程池就实现了。

总的来说增加和构造函数都比较需要初始化方法,所以这个记忆要深刻一些。

最后奉上完整代码

public class ThreadExcutor<Job extends Runnable> {private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());private final LinkedList<Job> jobs =new LinkedList<>();private static final int DEFAULT_WORKER_NUMBERS = 5;private  int workerNum = DEFAULT_WORKER_NUMBERS;private static final int MAX_WORKER_NUMBERS = 10;private static final int MIN_WORKER_NUMBERS = 1;public ThreadExcutor(){InitialWorkers(DEFAULT_WORKER_NUMBERS);}//将worker放入wokers集合中,然后开始让worker线程执行。private void InitialWorkers(int num){for (int i = 0; i < num; i++) {Worker worker = new Worker();workers.add(worker);Thread thread = new Thread(worker,"ThreadPool-Worker-"+ i);thread.start();}}//判断num是否在最大和最少工人范围之间,在的话将工人数量赋值num,不在的话num大于max就复制max,小于max就赋值minpublic ThreadExcutor(int num){this.workerNum = num > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS : Math.max(num, MIN_WORKER_NUMBERS);InitialWorkers(workerNum);}//如果工作不为空,就将工作放入工作队列中,然后唤醒工作队列public void execute(Job job){if (job != null){synchronized (jobs){jobs.addLast(job);jobs.notify();}}}//遍历工人集合,一个一个关闭public void shutdown(){for (Worker worker : workers) {worker.shutdown();}}//这里初始化时对jobs有操作,所以也对jobs进行加锁。添加工人时需要判断加上原来的工人是否超过了最大的工人数,//如果超过了就将num赋值成不超过最大工人的最大数量,然后去用num数初始化,并且将工人数更新成最新。public void addWorks(int num){synchronized (jobs){if (num + workerNum > MAX_WORKER_NUMBERS){num = MAX_WORKER_NUMBERS - workerNum;}InitialWorkers(num);workerNum += num;}}//先检查删除数是否在工人数之内,不在就抛出超出范围的异常。然后在工人集合中不断地取工人,然后进行shutdown,最后workerNum更新成剩下的工人数。public void removeWorkers(int num){synchronized (jobs){if(num >= workerNum){throw new IllegalArgumentException("超出范围");}int count = 0;while (count < num){Worker worker = workers.get(count);if (workers.remove(worker)){worker.shutdown();count++;}}workerNum -= count;}}//获取工作数public int getJobSize(){return jobs.size();}//worker主要是从jobs中拿工作,拿不到等,拿到了执行。class Worker implements Runnable{private volatile boolean running = true;@Overridepublic void run() {while (running){Job job = null;synchronized (jobs){while (jobs.isEmpty()){try{jobs.wait();} catch (Exception e){Thread.currentThread().interrupt();return;}}job = jobs.removeFirst();}if (job != null){job.run();}}}public void shutdown(){running = false;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/738113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工程经济学一

工程项目&#xff1a; 工程项目是指为完成某一独特的产品、服务或任务所做的一次性努力。又称建设项目、基本建设项目、投资建设项目或建设工程项目。 工程项目前评价&#xff1a; 是项目建议书和可行性研究阶段进行的&#xff0c;是项目开工前对 拟建项目的必要性和可能性进…

删除、创建、验证Kafka安装自带的__consumer_offsets topic

删除Kafka自带Topic 一般情况下&#xff0c;你删除Kafka自带的__consumer_offsets topic&#xff0c;会报错提示不能删除。 倔强的你直接找到zookeeper删掉了它&#xff0c;list查看确实没有这个topic了&#xff0c;但是这会导致消费者和偏移量无法记录。 创建Kafka自带的Topi…

zabbix5监控tomcat

zabbix tomcat客户端配置 1、配置tomcat catalina.sh文件 CATALINA_OPTS"$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port12345 -Dcom.sun.management.jmxremote.authenticatefalse -Dcom.sun.management.jmxremote.sslfalse -Djav…

smart-doc 社区 Committer 晋升公告

我们非常荣幸地宣布&#xff0c;经过 PMC 委员会的提名和讨论&#xff0c;社区成员李星志&#xff08;GitHub ID: netdied&#xff09;、陈琪&#xff08;GitHub ID: chenqi146&#xff09;和李兵&#xff08;GitHub ID: abing22333&#xff09;正式晋升为同程旅行 smart-doc 开…

Vue3全家桶 - Vue3 - 【3】模板语法(指令+修饰符 + v-model语法糖)

一、模板语法 主要还是记录一些指令的使用和vue2的区别&#xff1b;vue3指令导航&#xff1b; 1.1 v-text 和 v-html 指令的区别&#xff1a; v-text&#xff1a; 更新元素的文本内容&#xff1b;v-text 通过设置元素的 textContent 属性来工作&#xff0c;因此它将覆盖元素…

数据结构:静态链表(编程技巧)

链表的元素用数组存储&#xff0c; 用数组的下标模拟指针。 一、理解 如果有些程序设计语言没有指针类型&#xff0c;如何实现链表&#xff1f; 在使用指针类型实现链表时&#xff0c;我们很容易就可以直接在内存中新建一块地址用于创建下一个结点&#xff0c;在逻辑上&#x…

3、设计模式之工厂模式

工厂模式是什么&#xff1f;     工厂模式是一种创建者模式&#xff0c;用于封装和管理对象的创建&#xff0c;屏蔽了大量的创建细节&#xff0c;根据抽象程度不同&#xff0c;主要分为简单工厂模式、工厂方法模式以及抽象工厂模式。 简单工厂模式 看一个具体的需求 看一个…

重拾C++之菜鸟刷算法第11篇---回溯算法(上)

今天是个好日子&#xff0c;二月二龙抬头&#xff0c;龙年龙日龙抬头&#xff0c;顺风顺水好兆头&#xff0c;万事万物开好头&#xff0c;金银珠宝往家里走&#xff01;offer往家走&#xff01; 回溯算法 回溯法可以解决的问题 组合问题&#xff1a;N个数里面按照一定规则找…

华为交换机创建端口组

文章目录 创建永久端口组解散永久端口组创建临时端口组总结 创建永久端口组 [SW3]port-group ?STRING<1-32> Port-group name \\表示用包含1到32个字符的字符串&#xff0c;给端口组其个名字&#xff0c;这种是创建永久组的group-member Add port to current port-g…

django动态表技术(根据日期,年月日)方法一

方法一&#xff1a; 第一步&#xff1a;在models创建一个类&#xff0c;里边存放数据表中需要的字段&#xff0c;如下 class TemplateModel(models.Model):NowTime models.CharField(max_length5)name models.CharFiedld(max_length5)class Meta:abstract True # 基础类设…

【C#语言入门】18. 事件详解(下)

【C#语言入门】18. 事件详解&#xff08;下&#xff09; 三、事件的声明 事件的声明 完整声明简略声明&#xff08;字段式声明。field-like&#xff09; 完整声明 class EventExample1 {static void Main(string[] args){Customer customer new Customer();Waiter waiter…

Vue3之通过Vue.config.globalProperties注册全局属性

Vue3之通过Vue.config.globalProperties注册全局属性 文章目录 Vue3之通过Vue.config.globalProperties注册全局属性1. Vue.config.globalProperties2. 注册全局属性1. 注册方式12. 注册方式2 3. 在setup函数中获取 1. Vue.config.globalProperties Vue2中使用Vue.prototype.自…

面向对象(精髓)变继承关系为组和关系(_Decorator模式)

在软件开发中&#xff0c;设计模式是解决常见问题的可重用解决方案。在面向对象编程中&#xff0c;继承和组合是两种常用的代码复用方式。然而&#xff0c;随着软件需求的不断变化&#xff0c;我们需要更灵活的设计方式来应对不断变化的需求。在本文中&#xff0c;我们将讨论从…

计算机网络——TCP/IP网络层次模型

计算机网络——TCP/IP网络层次模型 TCP/IP网络模型的起源TCP/IP网络层次的结构TCP/IP如何交互 TCP/IP协议栈TCP/IP协议栈主要协议 TCP/IP 和 OSI之间的区别面向连接和无连接面向连接三次握手&#xff0c;四次挥手 无连接 我们上一次了解了OSI的网络层次模型&#xff0c;如果还没…

Linux学习-内存管理

目录 内存管理 malloc free 使用 字符串存储申请堆区 自主输入个数&#xff0c;然后通过malloc在程序中申请空间&#xff0c;不用必须提前指定大小 内存溢出 内存泄漏 内存碎片 内存管理 函数名就是指向该函数的函数指针。 堆区是自低向高&#xff0c;栈区是自高向低…

代理模式的学习

1. 概念 1.代理模式是什么&#xff1f; 其实就是选一个中间人&#xff0c;可以理解为中介&#xff0c;如果要买房子&#xff0c;先和中介去商量&#xff0c;中介和房主去商量&#xff0c;这样。 2.为什么需要代理模式&#xff1f; 其实还是为了安全吧&#xff0c;代理模式中…

ffmpeg日记4001-原理介绍-视频切割原理

原理 打开输入---->打开输出---->根据输入来创建流---->拷贝流设置---->循环读帧---->判断时间点是否到达切割点&#xff0c;并做设置---->设置pts和dts---->写入---->善后 重点是pts和dts如何设置。参考《ffmpeg学习日记25-pts&#xff0c;dts概念的…

ftp速度太慢只有几十k,怎么解决?

FTP是目前许多企业日常运营中还在用的文件传输方式。虽然比较普遍&#xff0c;然而&#xff0c;许多用户在使用FTP时经常遇到速度缓慢的问题&#xff0c;有时甚至只有几十KB/s。这不仅影响工作效率&#xff0c;还可能导致许多数据传输的延迟的问题。本文将探讨FTP速度慢的原因&…

计算机服务器中了faust勒索病毒怎么解密,faust勒索病毒解密工具流程

在互联网飞速发展的今天&#xff0c;越来越多的企业走向了数字化办公模式&#xff0c;许多企业开始利用网络计算机开展各项工作业务&#xff0c;网络也为企业的生产效率提供了极大便利&#xff0c;但网络中存在许多恶意威胁。近日&#xff0c;云天数据恢复中心接到许多企业的求…

关于一个数组的小细节

机缘 写一个矩阵转置的代码用到了数组 收获 了解到输入数组的大小要在数组前面而不能先定义数组然后再输入 举例 #include <stdio.h>int main() {int a, b;scanf("%d %d ",&a,&b);int arr[a][b];for(int i 0;i < a;i){for(int j 0;j < b…