手写JAVA线程池

news2024/11/23 15:22:09

前言

手写一个简单的java线程池:重点关注,如何确保一直有运行的线程?如何确保线程消费提交的任务信息?。一直保存有运行的线程底层使用的是死循环。使用消息队列确保信息的提交和消费。消息队列使用先进先出原则。

步骤

线程池核心点 :复用机制

  • 1、提前创建好固定的线程一直在运行状态----死循环实现
  • 2、提交的线程任务缓存到一个并发队列集合中,交给我们正在运行的线程执行
  • 3、正在运行的线程就从队列中获取该任务执行

1、创建固定线程

根据传入的参数,确定要生成几个一直运行的线程。比如传入的参数是2,就会创建出2个一直运行的线程。一直运行的线程使用死循环来实现。

public class MyTestExecutors {
    private List<WorkThread> workThread;

    /**
     * 最大线程数
     * @param maxThreadCount
     */
    public MyTestExecutors(int maxThreadCount){
        //提前创建好固定的线程一直在运行状态---死循环实现
        workThread = new ArrayList<WorkThread>(maxThreadCount);
        for (int i = 0; i < maxThreadCount; i++) {
            new WorkThread().start();
        }
    }

    class WorkThread extends Thread{
        @Override
        public void run() {
            while (true){

            }
        }
    }
}

2、提交任务到消息队列

提交的线程任务缓存到一个并发队列集合中,交给我们正在运行的线程执行。

提示:offer()方法是Java队列中经常使用的方法,它的作用是向队列尾部添加一个元素。具体来说,offer()方法会将指定的元素插入到此队列的末尾,如果队列已满,它将返回false。否则,它会返回true,表示已成功添加了元素。

    /**
     * 线程任务缓存到一个并发队列集合
     * @param command
     * @return
     */
    public boolean execute(Runnable command){
        return runnableDeque.offer(command);
    }

public class MyTestExecutors {
    private List<WorkThread> workThread; //工作线程
    private BlockingDeque<Runnable> runnableDeque; //队列


    /**
     * @param maxThreadCount 最大线程数
     * @param dequeSize      缓存消息队列
     */
    public MyTestExecutors(int maxThreadCount,int dequeSize){
        //1、限制队列容量缓存
        runnableDeque = new LinkedBlockingDeque<Runnable>(dequeSize);
        //2、提前创建好固定的线程一直在运行状态---死循环实现
        workThread = new ArrayList<WorkThread>(maxThreadCount);
        for (int i = 0; i < maxThreadCount; i++) {
            new WorkThread().start();
        }

    }

    class WorkThread extends Thread{
        @Override
        public void run() {
            while (true){

            }
        }
    }

    /**
     * 线程任务缓存到一个并发队列集合
     * @param command
     * @return
     */
    public boolean execute(Runnable command){
        return runnableDeque.offer(command);
    }

    public static void main(String[] args) {
        MyTestExecutors testExecutors = new MyTestExecutors(2, 2);
        for (int i = 0; i < 10; i++) {
            final int finalI = i;
            testExecutors.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+","+finalI);
                }
            });
        }
    }
}

3、线程消费消息队列

正在运行的线程就从队列中获取该任务执行

    class WorkThread extends Thread{
        @Override
        public void run() {
            while (true){
                Runnable runnable = runnableDeque.poll();
                if(runnable != null){
                    runnable.run();
                }
            }
        }
    }

4、测试

2个的情况,两个固定线程还未执行任务,且队列中只缓存了两个线程任务。

在这里插入图片描述

4个的情况,固定两个线程正在执行任务,队列中缓存了两个线程任务。
在这里插入图片描述

5、线程停止【完整代码】

如何在线程任务执行完成后,停止两个一直存在的线程。需要将死循环的条件改变,通过给一个标志位。在任务结束后,将该标志位设置为false,同时需要判断,队列中的任务是否执行结束。队列中缓存的任务全部结束,才停止线程。

while (isRun || runnableDeque.size()>0)

package com.grg.demo.testDemo02;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @author zyz
 * @version 1.0
 * @data 2023/7/11 23:01
 * @Description: 手写线程池
 *  线程池核心点 :复用机制 -----
 *  1、提前创建好固定的线程一直在运行状态----死循环实现
 *  2、提交的线程任务缓存到一个并发队列集合中,交给我们正在运行的线程执行
 *  3、正在运行的线程就从队列中获取该任务执行
 */
public class MyTestExecutors {
    private List<WorkThread> workThread; //工作线程
    private BlockingDeque<Runnable> runnableDeque; //队列
    private Boolean isRun = true;

    /**
     *
     * @param maxThreadCount 最大线程数
     * @param dequeSize      缓存消息队列
     */
    public MyTestExecutors(int maxThreadCount,int dequeSize){
        //2、限制队列容量缓存
        runnableDeque = new LinkedBlockingDeque<Runnable>(dequeSize);
        //1、提前创建好固定的线程一直在运行状态---死循环实现
        workThread = new ArrayList<WorkThread>(maxThreadCount);
        for (int i = 0; i < maxThreadCount; i++) {
            new WorkThread().start();
        }

    }

    class WorkThread extends Thread{
        @Override
        public void run() {
            while (isRun || runnableDeque.size()>0){
                Runnable runnable = runnableDeque.poll();
                if(runnable != null){
                    runnable.run();
                }
            }
        }
    }

    /**
     * 线程任务缓存到一个并发队列集合
     * @param command
     * @return
     */
    public boolean execute(Runnable command){
        return runnableDeque.offer(command);
    }

    public static void main(String[] args) {
        MyTestExecutors testExecutors = new MyTestExecutors(2, 2);
        for (int i = 0; i < 10; i++) {
            final int finalI = i+1;
            testExecutors.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+","+finalI);
                }
            });
        }
        testExecutors.isRun = false;
    }
}

在这里插入图片描述

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

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

相关文章

漏洞复现 || OpenSNS远程命令执行漏洞

免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#xff0c;尊重社会公德&#xff0c;不得危害网络安全&#xff0c;不得利用网络从事危害国家安全、荣誉和利益&#xff0c;未经授权请勿利用文章中的技术资料对任何计…

力扣 | 二分查找模板

力扣&#xff1a;二分查找 文章目录 &#x1f4da;二分查找&#x1f4da;模板I&#x1f449;x 的平方根&#x1f449;猜数字大小&#x1f449;搜索旋转排序数组 &#x1f4da;模板II&#x1f449;第一个错误的版本&#x1f449;寻找峰值 &#x1f4da;模板III&#x1f449;在排…

photoshop制作法线和凹凸贴图

做个选区 Ctrlj 法线贴图 生成凹凸贴图

Vue实现多语言(i18n)

第一步 安装i18n插件。 npm install vue-i18n第二步 在src目录下&#xff0c;创建一个【language】文件夹&#xff0c;并创建两个语言包js文件。 中文语言包&#xff1a;【zh.js】 英文语言包&#xff1a;【en.js】 第三步 完善en.js文件和zh.js文件。两个文件的结构要相…

系统架构设计师-项目管理

目录 一、盈亏平衡分析 二、进度管理 1、WBS工作分解结构 2、进度管理流程 &#xff08;1&#xff09;活动定义 &#xff08;2&#xff09;活动排序 &#xff08;3&#xff09;活动资源估算&#xff1a; &#xff08;4&#xff09;活动历时估算&#xff1a; &#xff08;5&…

谷歌浏览器添加首页快捷方式,并设置默认搜索引擎为百度

目录 1、添加首页快捷方式 ​2、谷歌浏览器设置默认搜索引擎 1、添加首页快捷方式 &#xff08;1&#xff09;首先要保证当前的默认搜索引擎为Google才可以添加首页的快捷方式。 &#xff08;2&#xff09;回到首页即可添加和自定义快捷方式的url &#xff08;3&#xff09;默…

Linux——系统文件IO(文件操作符 详解+代码)

文件操作符 1.回顾C语言文件接口总结 2.系统文件IO2.1 open函数介绍2.2代码测试2.3Q :fd为什么是3&#xff1f;012去哪里了&#xff1f;A: 3.如何理解Linux下一切皆文件 1.回顾C语言文件接口 写文件 #include <stdio.h> #include <string.h> int main() { FILE *…

【双指针】24. 两两交换链表中的节点

24. 两两交换链表中的节点 解题思路 dummyNode指向22 指向11 指向3然后移动指针 开始交换 3 4 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* L…

OpenAI GPT-4 Code Interpreter测试

OpenAI GPT-4 Beta版本Code Interpreter功能分析 OpenAI最近在GPT-4中推出了Code Interpreter功能的Beta版本&#xff0c;它是ChatGPT的一个版本&#xff0c;可以编写和执行Python代码&#xff0c;并处理文件上传。以下是对其表现的基本分析。 主要功能 文件信息获取&#xf…

Flutter入门教程(一),2023最新版包含安装,初始化!简单易懂!

Flutter入门教程&#xff08;一&#xff09;&#xff0c;2023最新版包含安装&#xff0c;初始化&#xff01;简单易懂&#xff01; Flutter介绍 首先&#xff0c;在一切的开始之前我们来介绍一下什么是Flutter&#xff0c;Flutter 是一个由 Google 开发的开源移动应用程序开发…

Openlayers实战:加载静态图片作为底图

我们经常会看到一些商场地图或者其他的静态图展示的情况,在Openlayers实战中,我们加载静态图片,使其成为底图,通过缩放,来展示各个部分。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑师兰特(CSDN) * @此源代码版权归大剑师兰特所有,可供学习或…

回首2023上半年:成长、思考、感恩

文章目录 每日一句正能量前言一、目标达成情况总结二、工作和学习成果总结三、下半年规划总结四、个人想法 后记附录 每日一句正能量 做一个向日葵族&#xff0c;面对阳光&#xff0c;不自艾自怜&#xff0c;每天活出最灿烂的自己。曾经拥有的&#xff0c;不要忘记。不能得到的…

【JAVA】定时任务之借阅到期自动催还

该篇主要以定时任务为主&#xff0c;通知略为记录 一. 定时任务逻辑代码 定时任务文件 TaskScheduling.java package org.springblade.modules.task;import lombok.extern.slf4j.Slf4j; import org.springblade.modules.archiveAdvantage.service.IArchiveBorrowService; im…

Pytorch基本使用—激活函数

✨1 介绍 ⛄ 1.1 概念 激活函数是神经网络中的一种数学函数&#xff0c;它被应用于神经元的输出&#xff0c;以决定神经元是否应该被激活并传递信号给下一层。常见的激活函数包括Sigmoid函数、ReLU函数、Tanh函数等。 &#x1f384; 1.2 性质 激活函数是神经网络中的一种重…

Markdown基本用法

目录 1 字体倾斜 1.1 加* 1.2 加_ 2 字体加粗 2.1 加** 2.2 加__ 3 字体上带删除线 4 文字变标题 5 超链接 5.1 直接输入地址 5.2 将超链接改成文字 5.2.1 同行写法 5.2.2 不同行写法 6 文字前加 6.1 号 6.2 *号 6.3 -号 7 有序列表 8 …

【微信小程序创作之路】- 小程序常用页面样式

【微信小程序创作之路】- 小程序常用页面样式 第四章 微信小程序用页面样式 文章目录 【微信小程序创作之路】- 小程序常用页面样式前言一、总体样式--全局样式and局部样式1.全局样式2.局部样式 二、Flex布局&#x1f349;&#x1f349;&#x1f349;rpx单位 三、样式导入四、…

HEGERLS四向穿梭车的调度算法如何解决同层多车时车辆路径规划和避让的问题?

纵观全球&#xff0c;消费需求正在发生转变&#xff0c;无论是个体消费还是企业消费&#xff0c;呈现出个性化、定制化、网络化的趋势。因此生产企业面临着产品多样化、订单碎片化、服务定制化的新挑战&#xff0c;仓储密集存储、超大拆零作业量需求愈加明显&#xff0c;且竞争…

苹果平板用不用买原装笔?ipad平替电容笔排行榜

我们应该都知道&#xff0c;第一款ipad早诞生于十年前&#xff0c;如今已是家喻户晓的平板电脑产品。ipad版本系列的更新非常迅速&#xff0c;销售也非常火爆。其中&#xff0c;iPad的配件起到了很大的作用&#xff0c;比如我们今天要介绍的这款电容笔&#xff0c;这款ipad的配…

vue3+ts中常用的两个按钮选择事件写法

1. 效果演示 2.vue3单页面代码演示 <template><div class"btns"><divv-for"(item, index) in nams"click"btnCol(index)":class"current index ? active : btn">{{ item }}</div></div><div clas…

【MySQL】从零开始的JDBC编程

1、JDBC的认识 学了这么久的 MySQL&#xff0c;我们一直采用的都是 MySQL 软件自带的客户端&#xff08;黑框框&#xff09;&#xff0c;来进行跟MySQL服务器进行交互。但是在实际开发中我们很少在黑框框中手动输入SQL&#xff0c;大多数都是通过代码自动执行SQL的。既然大多数…