自定义线程池 ThreadPoolExecutor

news2024/9/29 9:19:57

ThreadPoolExecutor 自定义线程池

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}
参数功能
corePoolSizethe number of threads to keep in the pool, even if they are idle.
maximumPoolSizethe maximum number of threads to allow in the pool.
keepAliveTimewhen the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
unitthe time unit for the {@code keepAliveTime} argument
workQueuethe queue to use for holding tasks before they are executed. This queue will hold only the {@code Runnable} tasks submitted by the {@code execute} method.

Java线程池的工作流程

在这里插入图片描述

前置条件执行步骤举例
首先检测 线程池运行状态如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。当试图通过excute方法将一个Runnable任务添加到线程池中时,按照如下顺序来处理
如果workerCount < corePoolSize创建并启动一个线程来执行新提交的任务。如果线程池中的线程数量少于corePoolSize,即使线程池中有空闲线程,也会创建一个新的线程来执行新添加的任务
如果workerCount >= corePoolSize,线程池内的阻塞队列未满则将任务添加到该阻塞队列中。如果线程池中的线程数量大于等于corePoolSize,但缓冲队列workQueue未满,则将新添加的任务放到workQueue中,按照FIFO的原则依次等待执行(线程池中有线程空闲出来后依次将缓冲队列中的任务交付给空闲的线程执行)
如果workerCount >= corePoolSize,线程池内的阻塞队列已满,但 workerCount < maximumPoolSize创建并启动一个线程来执行新提交的任务。如果线程池中的线程数量大于等于corePoolSize,且缓冲队列workQueue已满,但线程池中的线程数量小于maximumPoolSize,则会创建新的线程来处理被添加的任务
如果 workerCount >= corePoolSize,线程池内的阻塞队列已满,且workerCount >= maximumPoolSize则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。如果线程池中的线程数量等于maximumPoolSize,有4种处理方式(该构造方法调用了含有5个参数的构造方法,并将最后一个构造方法为RejectedExecutionHandler类型,它在处理线程溢出时有4种方式,这里不再细说,要了解的,自己可以阅读下源码)
注意:
当线程池中的线程数量大于corePoolSize时,如果里面有线程的空闲时间超过了keepAliveTime,就将其移除线程池,这样可以动态地调整线程池中线程的数量。

线程任务

public class Task implements Runnable {
    private final String name;

    public Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " → " + name + " Start Time = " + new Date());
        processCommand();
        System.out.println(Thread.currentThread().getName() + " → " + name + " End   Time = " + new Date());
    }

    private void processCommand() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

自定义线程池

public class CustomThreadPool {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "线程: Start at: " + new Date());

        // 创建等待队列
        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(20);

        // 创建线程池、池中保存的线程数为3,允许的最大线程数为5
        ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 50, TimeUnit.MILLISECONDS, blockingQueue);

        // 创建七个任务
        // 每个任务会在一个线程上执行
        for (int i = 1; i < 10; i++) {
            System.out.println("添加了第" + i + "个任务类");
            pool.execute(new Task("线程任务" + i));
        }

        // 关闭线程池
        pool.shutdown();

        System.out.println(Thread.currentThread().getName() + "线程: 打卡:" + new Date());

        long i = 0;
        while (!pool.isTerminated()) {
            // wait for all tasks to finish
            i++;
        }

        System.out.println(Thread.currentThread().getName() + "线程: Finished all threads at:" + new Date() + ". isTerminated 判断次数 " + i);
    }
}

执行结果分析

执行结果
main线程: Start at: Fri May 19 18:28:52 CST 2023进入main线程
添加了第1个任务类构建任务放入线程池
添加了第2个任务类
添加了第3个任务类
添加了第4个任务类
添加了第5个任务类
添加了第6个任务类
添加了第7个任务类
添加了第8个任务类
添加了第9个任务类
添加了第10个任务类
main线程: 打卡:Fri May 19 18:28:52 CST 2023主线程打个卡
pool-1-thread-2 → 线程任务2 Start Time = Fri May 19 18:28:52 CST 2023线程池开始分配线程执行线程任务
pool-1-thread-1 → 线程任务1 Start Time = Fri May 19 18:28:52 CST 2023
pool-1-thread-3 → 线程任务3 Start Time = Fri May 19 18:28:52 CST 2023
pool-1-thread-2 → 线程任务2 End Time = Fri May 19 18:28:55 CST 2023
pool-1-thread-2 → 线程任务4 Start Time = Fri May 19 18:28:55 CST 2023
pool-1-thread-3 → 线程任务3 End Time = Fri May 19 18:28:55 CST 2023
pool-1-thread-1 → 线程任务1 End Time = Fri May 19 18:28:55 CST 2023
pool-1-thread-1 → 线程任务6 Start Time = Fri May 19 18:28:55 CST 2023
pool-1-thread-3 → 线程任务5 Start Time = Fri May 19 18:28:55 CST 2023
pool-1-thread-2 → 线程任务4 End Time = Fri May 19 18:28:58 CST 2023
pool-1-thread-2 → 线程任务7 Start Time = Fri May 19 18:28:58 CST 2023
pool-1-thread-3 → 线程任务5 End Time = Fri May 19 18:28:58 CST 2023
pool-1-thread-1 → 线程任务6 End Time = Fri May 19 18:28:58 CST 2023
pool-1-thread-3 → 线程任务8 Start Time = Fri May 19 18:28:58 CST 2023
pool-1-thread-1 → 线程任务9 Start Time = Fri May 19 18:28:58 CST 2023
pool-1-thread-2 → 线程任务7 End Time = Fri May 19 18:29:01 CST 2023
pool-1-thread-2 → 线程任务10 Start Time = Fri May 19 18:29:01 CST 2023
pool-1-thread-3 → 线程任务8 End Time = Fri May 19 18:29:01 CST 2023
pool-1-thread-1 → 线程任务9 End Time = Fri May 19 18:29:01 CST 2023
pool-1-thread-2 → 线程任务10 End Time = Fri May 19 18:29:04 CST 2023
main线程: Finished all threads at:Fri May 19 18:29:04 CST 2023. isTerminated 判断次数 25692088316所有线程全部执行完毕
从结果中可以看出,10 个任务是在线程池的 3 个线程上执行的

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

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

相关文章

Arduino ESP8266+RC522+阿里云 物联网入户控制RFID门禁系统

前言 根据项目结课报告改编而成&#xff0c;可能更适合作为一份文档而不是一篇记录类型的博客&#xff0c;没有留存接线图和运行图片&#xff0c;感到抱歉。 使用的板子是YwRobot的ESP8266板子&#xff0c;使用Arduino IDE开发&#xff0c;用到了舵机、按钮、人体感应传感器、…

Unity UI -- (4)用图像创建菜单背景

添加一个基础的设置菜单背景 设置菜单的元素会安放在一个简单的矩形区域上。我们用一个Image对象来创建这个矩形。 1. 首先&#xff0c;我们暂时停用Title Text和Settings Button游戏物体。这样会让我们的Canvas看起来更清爽。 2. 在Hierarchy中&#xff0c;点击右键&#xff0…

探索云原生世界:当前最受欢迎的技术和趋势

文章目录 探索云原生世界&#xff1a;当前最受欢迎的技术和趋势引言&#xff1a;一、云原生概述&#xff1a;1. 什么是云原生&#xff1f;2. 为什么云原生重要&#xff1f;3. 云原生的核心原则和特征。4. 云原生的优势和挑战。 二、核心技术与工具&#xff1a;1. Kubernetes&am…

C语言qsort函数、活字印刷、cmd窗口

一、qsort函数 qsort函数就是快排&#xff0c;可以不用写那么一长串的代码了qvq&#xff0c;要用到stdlib.h库文件 那么具体用法就是 oid qsort(void* base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*)); 当然我们还要用一个比较函数来确定快排…

手机APP性能测试工具PerfDog性能狗安装教程及简单使用

一、前言 PerfDog是一个由腾讯研发的主流性能测试软件。可以提高软件和游戏的运行效率&#xff0c;支持iOS/安卓在移动平台上的性能测试和分析&#xff0c;快速定位和分析性能问题等。无需安装&#xff0c;即插即用&#xff0c;减少繁琐的测试障碍&#xff0c;安卓设备不需要RO…

PCB基础~PCB介质,Vias

PCB介质 • 一般的介质材料 – FR-4&#xff08;玻璃纤维和环氧基树脂交织而成&#xff09; • 最常和最广泛使用&#xff0c;相对成本较低 • 介电常数&#xff1a;最大4.7&#xff0c; 4.35500Mhz,4.341Ghz • 可承受的最高信号频率是2Ghz(超过这个值&#xff0c;损耗和串扰…

IDEA中怎么把jar包导入项目中

大作业让生成一个pdf&#xff0c;查找资料发现可以通过pdfbo相关函数调用&#xff0c;但本地缺少这个文件&#xff0c;以这个文件为例子。 一、下载 下载去Apache上下载&#xff0c;Apache PDFBox | Download&#xff0c;&#xff0c;结合自己的java版本啥的下载就行。 我是…

java中使用java8的stream报错java.lang.IllegalStateException: Duplicate key

一、java.lang.IllegalStateException: Duplicate key报错的原因 map的key重复导致的报错Duplicate key 二、java.lang.IllegalStateException: Duplicate key报错的解决方式 list.stream().collect()就是把一个List的查询数据集合转为一个Map&#xff0c;java8的stream方式…

UE5 C++类如何打印日志?

UE5 插件开发指南 前言0. 什么是日志?1.在哪里可以查看日志呢?2. 日志有哪些等级?3. 如何打印到屏幕上?4. 如何更专业的记录日志?4.0 UE_LOG宏语法4.1 自定义日志类别4.2 插件中的日志类别定义前言 在回答这个问题之前,先要给萌新科普一下:什么是日志?以及,在哪里查看日…

自己动手写一个加载器

前言 当在 linux 命令行中 ./ 运行一个程序时&#xff0c;实际上操作系统会调用加载器将这个程序加载到内存中去执行。为了探究加载器的行为&#xff0c;今天我们就自己动手写一个简单的加载器。 工作原理 加载器的工作原理&#xff1a; 从磁盘读取 bin 文件到内存&#xf…

【Python html常用标签】零基础也能轻松掌握的学习路线与参考资料

学习路线 要深入了解Python html常用标签&#xff0c;需要遵循以下学习路线&#xff1a; 1.1 HTML基础知识&#xff1a;了解HTML语言的起源&#xff0c;HTML文档结构和基本标签。学习HTML标签包含但不限于文本标签&#xff0c;图像标签&#xff0c;链接标签&#xff0c;表格标…

canvas的HTML和JavaScript

文章目录 一、canvas元素二、前期准备1. 坐标系2. canvas属性① 获取canvas元素② 把canvas实例化为2D③ 设置路径颜色④ 设置路径宽度⑤ 设置路径末端形状⑥ 设置路径相连时的相连部分形状⑦ 透明度⑦ 虚线 三、绘制图行1. 绘制线段2. 绘制三角形① 空心三角形② 实心三角形 3…

大学四年,我建议你这么学网络安全

在所有关注我的朋友中&#xff0c;大致分为两类&#xff0c;一类是社会人士&#xff0c;有的是安全老手&#xff0c;有的是其它工作但对安全感兴趣的朋友&#xff0c;另一类应该就是大学生了。 尤其随着国家的号召和知识的普及&#xff0c;越来越多的人开始对网络安全感兴趣&a…

ffmpeg日记1011-过滤器-语法高阶,逻辑,函数使用

Author: wencoo Blog&#xff1a;https://wencoo.blog.csdn.net/ Date: 19/05/2023 Details:文章目录 摘要什么是时间线编辑哪些filter支持时间线编辑时间线编辑中&#xff0c;可以使用哪些预设函数常用预设函数功能即使用方法if(x, y)if(x, y, z)gt(x, y)gte(x, y)lt(x, y)lte…

AHB-to-APB Bridge——04apb_tran、apb_if、apb_drv、mem、apb_mon、apb_agt

apb_if放入所有apb需要的信号&#xff0c;以及cb ifndef APB_IF_SV define APB_IF_SVinterface apb_if;logic pclk;logic prst;logic penable;logic …

C++的stack和queue

stack和queue 1.stackstack的模拟实现 2.queuequeue的模拟实现 3.容器适配器3.1. 什么是容器适配器3.2. STL标准库中stack和queue的底层结构3.3. deque的简单介绍3.3.1. deque原理介绍3.3.2. deque的缺陷3.3.3. 为什么选择deque作为stack和queue的底层默认容器 1.stack stack的…

深度学习-第T7周——咖啡豆识别

深度学习-第T7周——咖啡豆识别 深度学习-第T7周——咖啡豆识别一、前言二、我的环境三、前期工作1、导入数据集2、查看图片数目 四、数据预处理1、 加载数据1、设置图片格式2、划分训练集3、划分验证集4、查看标签 2、数据可视化3、检查数据4、配置数据集 五、搭建CNN网络六、…

Vue3+TS知识点补充

一、关于Ref 1.shallowRef() shallowRef 是 Vue 3 中新引入的响应式数据类型之一&#xff0c;它与 ref 类型非常相似&#xff0c;但是有一些不同点。 不同的是&#xff0c;shallowRef 只会对其包装的对象进行浅层次的响应式处理&#xff0c;即如果这个对象的子属性发生改变&…

软件测试——黑盒测试

1.测试概述 1.1综述 本测试报告为计算机程序能力在线测评系统的黑盒测试&#xff0c;黑盒测试可以在不知道程序内部结构和代码的情况下进行&#xff0c;用来测试软件功能是否符合用户需求&#xff0c;是否达到用户预期目标&#xff0c;是否拥有较好的人机交互体验。 图1.1 黑…

media设备节点初始化与Video4Linux初始化

media设备节点初始化与Video4Linux初始化 文章目录 media设备节点初始化与Video4Linux初始化media设备节点初始化Video4Linux初始化 media设备节点初始化 media_devnode_init函数是一个内核初始化函数&#xff0c;用于在Linux内核启动期间进行设备节点初始化。 函数的主要作用…