首页 > 其他分享 >简易线程池的实现

简易线程池的实现

时间:2024-03-12 22:58:05浏览次数:14  
标签:jobs 实现 workerNum worker 简易 int num 线程

Worker的实现 

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

//worker主要是从jobs中拿工作,拿不到等,拿到了执行。
     class Worker implements Runnable{

       private volatile boolean running = true;

        @Override
        public 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就赋值min
    public 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就赋值min
    public 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;

        @Override
        public 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;
       }

    }
}

标签:jobs,实现,workerNum,worker,简易,int,num,线程
From: https://blog.csdn.net/weixin_62773644/article/details/136638095

相关文章

  • 在UniApp中实现对接PayPal支付
    基本的指南:获取PayPalAPI凭证:首先,你需要在PayPal开发者中心注册并创建一个应用。这将为你提供必要的API凭证,如ClientID和Secret,用于与PayPal的API进行通信。配置UniApp项目:在你的UniApp项目中,你需要配置PayPal的相关信息。这通常包括在manifest.json文件中设置支付相关......
  • GDCM:实现使用gdcm::Series类进行DICOM的序列化和反序列化操作(附完整源码)
    GDCM:实现使用gdcm::Series类进行DICOM的序列化和反序列化操作下面是一个使用GDCM库中的gdcm::Series类进行DICOM序列化和反序列化操作的示例代码:#include<iostream>#include"gdcmReader.h"#include"gdcmWriter.h"#include"gdcmGlobal.h"#include"gdcmSystem.......
  • GDCM:实现显示GDCM Dict(附完整源码)
    GDCM:实现显示GDCMDict要显示GDCM的字典(Dictionary),您可以使用GDCM提供的gdcm::Global类。以下是一个示例代码,用于显示GDCM字典的内容:#include<iostream>#include"gdcmGlobal.h"#include"gdcmDict.h"#include"gdcmDictEntry.h"intmain(){gdcm::Global......
  • 基于协同过滤的旅游推荐系统设计与实现
    1绪论1.1研究背景及意义1.2国内外研究现状1.3研究目标与意义1.4主要研究工作2相关理论介绍2.1HTML与JavaScript2.2MySQL数据库2.3协同过滤算法简介3系统分析与设计3.1系统需求分析3.1.1功能性需求3.1.2安全性需求3.2系统总体架构3.3功能模块设计3......
  • 利用Nginx正向代理实现局域网电脑访问外网
    引言在网络环境中,有时候我们需要让局域网内的电脑访问外网,但是由于网络策略或其他原因,直接访问外网是不可行的。这时候,可以借助Nginx来搭建一个正向代理服务器,实现局域网内电脑通过Nginx转发访问外网的需求。在工作中我遇到了一个类似的情况:在公司网络中,由于管理要求,局域网......
  • C语言数据结构实现酒店管理
    #include<stdio.h>#include<windows.h>#include<stdlib.h> #include<string.h>//用于用户验证 #defineMAX100//最大房间容量 #defineStytm20#definemAX1024//文件读取字符长 intfileHang(FILE*fp);intlength=0;//房间顺序 typedefintDataType;typ......
  • 采用Java实现论文查重
    这个作业属于哪个课程<软件工程2024(广东工业大学)>这个作业要求在哪里<个人项目>这个作业的目标<熟悉个人软件开发流程、熟悉各类工具的使用,学会用PSPG进行项目规划评估程序质量并优化程序>Gitee链接:https://github.com/jueshishuaimengou/yh/tree/main/3122......
  • Java项目源码基于springboot的家政服务平台的设计与实现
    大家好我是程序员阿存,在java圈的辛苦码农。辛辛苦苦板砖,今天要和大家聊的是一款Java项目源码基于springboot的家政服务平台的设计与实现,项目源码以及部署相关请联系存哥,文末附上联系信息。项目源码:Java基于springboot的家政服务平台的设计与实现.rar资源-CSDN文库项目简介:......
  • MYSQL: 表表达式(CTE)实现递归实例
    环境:MYSQL8.0 + windows10 1、在TEST数据库中创建 表CTE_TEST.CREATETABLE`test`.`cte_test`(test_idINT,test_nameVARCHAR(50),parent_test_idINT,created_byINT,creation_dateTIMESTAMP);例子数据:INSERTINTO`test`.`cte_test`(test_i......
  • windows、C++怎么看线程在哪个核上运行
    一.要在Windows系统上查看线程运行在哪个处理器核心上,可以使用Windows系统提供的一些工具和方法。在Windows中,可以使用以下几种方式来查看线程运行的处理器核心:使用任务管理器打开任务管理器:可以通过按下 Ctrl+Shift+Esc 组合键快速打开任务管理器,或者通过右键......