线程池工具类
线程池简述
为什么需要一个线程池工具类?
答:整个项目,用到线程执行任务的地方很多,不可能哪里用到就在那里直接new一个线程执行,这样资源得不到重复利用,一旦线程过多就会导致内存不足。
线程池的好处是什么?
答:使用线程池执行线程任务,当一个线程执行完成一个任务之后,线程资源回到线程池,资源得到重复利用。
线程池为什么使用自定义方式?
阿里文档推荐使用自定义线程池,因为java自带线程池都会有可能造成内存不足的问题。自定义线程池,根据服务器配置定制线程池核心线程、最大线程等,是最好的方式。
二、工具类代码和测试代码
导包
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency>
工具类
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;/*** 自定义线程创建工具类,创建线程池后不需要关闭** @author liangxn*/
public class ThreadPoolUtils {private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolUtils.class);private static ThreadPoolExecutor threadPool = null;private static final String POOL_NAME = "myPool";// 等待队列长度private static final int BLOCKING_QUEUE_LENGTH = 20000;// 闲置线程存活时间private static final int KEEP_ALIVE_TIME = 60 * 1000;private ThreadPoolUtils() {throw new IllegalStateException("utility class");}/*** 无返回值直接执行** @param runnable 需要运行的任务*/public static void execute(Runnable runnable) {getThreadPool().execute(runnable);}/*** 有返回值执行* 主线程中使用Future.get()获取返回值时,会阻塞主线程,直到任务执行完毕** @param callable 需要运行的任务*/public static <T> Future<T> submit(Callable<T> callable) {return getThreadPool().submit(callable);}public static synchronized ThreadPoolExecutor getThreadPool() {if (threadPool == null) {// 获取处理器数量int cpuNum = Runtime.getRuntime().availableProcessors();// 根据cpu数量,计算出合理的线程并发数int maximumPoolSize = cpuNum * 2 + 1;// 核心线程数、最大线程数、闲置线程存活时间、时间单位、线程队列、线程工厂、当前线程数已经超过最大线程数时的异常处理策略threadPool = new ThreadPoolExecutor(maximumPoolSize - 1,maximumPoolSize,KEEP_ALIVE_TIME,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(BLOCKING_QUEUE_LENGTH),new ThreadFactoryBuilder().setNameFormat(POOL_NAME + "-%d").build(),new ThreadPoolExecutor.AbortPolicy() {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor e) {LOGGER.warn("线程爆炸了,当前运行线程总数:{},活动线程数:{}。等待队列已满,等待运行任务数:{}",e.getPoolSize(),e.getActiveCount(),e.getQueue().size());}});}return threadPool;}
}
线程池的七个参数讲解
- corePoolSize:线程池核心大小。线程池中会维护最小的线程线程数量,即使这些线程处于空闲状态,他们也不会销毁,除非设置了allowCoreThreadTimeOut。
- maximumPoolSize:线程池最大线程数量。一个任务被提交到线程池以后,首先会找有没有空闲存活的线程,如果有则直接将任务提交给空闲线程,如果没有,就会缓存到工作队列中。如果工作队列满了,才会新建一个线程,然后从工作队列的头部去除一个任务交由新线程来处理,而将刚提交的任务放入工作队列的尾部。线程池不会无限制的去创建新线程,它会有一个最大线程数量限制,这个数量即由maximunPoolSize指定。
- keepAliveTime:空闲线程存活时间。一个线程如果处于空闲状态,且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程就会被销毁。
- unit:空闲线程存活时间单位。keepAliveTime的计量单位。
- workQueue:工作队列。新任务被提交以后,会进入到此工作队列中,任务调度时再从队列中取出任务。
- threadFactory:线程工厂。创建一个新线程使用的工厂,可以用来设定线程名
- hander:拒绝策略。当工作队列中的任务已达到最大限制,并且线程池中的线程数量已达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题。
四种工作队列
- ArrayBlockingQueue:基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中的线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经满了,则创建一个新的线程,如果线程数量已经达到了maxPoolSize,则会执行拒绝策略。
- LinkedBlockingQuene:基于链表的无界阻塞队列(其实最大容量为Integer.MAX)。按FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到了corePoolSize之后,再有新任务进来,会一直存在该队列,而不会去创建新的线程,知道maxPoolSize,因此使用该工作队列时,参数ma'xPoolSize其实是不起作用的。
- SynchronousQuene:一个不缓存任务的阻塞队列。生产者放入一个任务,必须等到消费者取出这个任务,也就是说,新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。
- PriorityBlockingQueue:具有优先级的无界阻塞队列,直到资源耗尽。默认情况下,元素采用自然排序升序排列。也可以自定义实现类compareTo()方法来指定元素排序规则,或者初始化PriorityBlockingQueue时,指定构造参数Comparator来对元素进行排序。但需要注意的是,不能保证同优先级元素的顺序。
四种拒绝策略
ThreadPoolExecutor.AbortPolicy | 直接抛出异常(默认拒绝策略) |
ThreadPoolExecutor.DiscardPolicy | 丢弃当前被拒绝的任务,而不抛出异常 |
ThreadPoolExecutor.DiscardOldestPolicy | 将工作任务中最老的任务丢弃,然后重新尝试接纳被拒绝的任务 |
ThreadPoolExecutor.CallerRunsPolicy | 在客户端中执行被拒绝的任务 |
例子1
Future<String> future = ThreadPoolUtils.submit(() -> {return "我有返回值哦";});try {logger.info(future.get());} catch (InterruptedException | ExecutionException e) {logger.error("任务超过指定时间未返回值,线程超时退出");}// 控制台打印日志:21:04:19.428 [main] INFO - 我有返回值哦
例子2
Future<String> future = ThreadPoolUtils.submit(() -> {return "我有返回值哦";});try {logger.info(future.get());} catch (InterruptedException | ExecutionException e) {logger.error("任务超过指定时间未返回值,线程超时退出");}// 控制台打印日志:21:04:19.428 [main] INFO - 我有返回值哦
例子3
int loop = 40;
for (int i = 0; i < loop; i++) {logger.info("任务{}", i);ThreadPoolUtils.execute(() -> {logger.info("干活好累");try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}logger.info("终于干完了");});}logger.info("我在这儿等着你回来等你回来");// 控制台打印:21:08:08.494 [main] INFO - 任务0............21:08:08.540 [main] INFO - 任务521:08:08.541 [main] INFO - 任务621:08:08.540 [myPool-4] INFO - 干活好累21:08:08.540 [myPool-1] INFO - 干活好累21:08:08.540 [myPool-3] INFO - 干活好累............21:08:08.543 [main] INFO - 任务2121:08:08.548 [main] INFO - 任务2221:08:08.548 [main] INFO - 任务2321:08:08.548 [myPool-21] INFO - 干活好累21:08:08.549 [main] INFO - 任务2421:08:08.549 [myPool-22] INFO - 干活好累21:08:08.549 [main] INFO - 任务2521:08:08.549 [myPool-23] INFO - 干活好累21:08:08.549 [main] INFO - 任务26............21:08:08.551 [myPool-1] INFO - 干活好累21:08:08.551 [myPool-6] INFO - 终于干完了21:08:08.551 [myPool-7] INFO - 终于干完了21:08:08.551 [myPool-5] INFO - 干活好累21:08:08.551 [main] INFO - 任务3521:08:08.551 [main] INFO - 任务3621:08:08.551 [main] INFO - 任务3721:08:08.551 [main] INFO - 任务3821:08:08.551 [main] INFO - 任务3921:08:08.551 [main] INFO - 我在这儿等着你回来等你回来21:08:08.551 [myPool-2] INFO - 干活好累21:08:08.551 [myPool-3] INFO - 干活好累21:08:08.551 [myPool-8] INFO - 干活好累21:08:08.551 [myPool-6] INFO - 干活好累21:08:08.551 [myPool-7] INFO - 干活好累21:08:08.552 [myPool-13] INFO - 终于干完了21:08:08.552 [myPool-12] INFO - 终于干完了............21:08:08.561 [myPool-7] INFO - 终于干完了21:08:08.561 [myPool-3] INFO - 终于干完了
例子4
// 测试10个线程使用工具类
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {executorService.submit(new Runnable() {@Overridepublic void run() {final String name = Thread.currentThread().getName();ThreadPoolUtils.execute(() -> {logger.info("[{}],干活好累", name);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}logger.info("[{}],终于干完了", name);});}});}logger.info("不用等他,我们先干");// 控制台打印:21:11:49.946 [main] INFO - 不用等他,我们先干21:11:49.991 [myPool-4] INFO - [pool-2-thread-7],干活好累21:11:49.991 [myPool-3] INFO - [pool-2-thread-2],干活好累21:11:49.991 [myPool-5] INFO - [pool-2-thread-5],干活好累21:11:49.991 [myPool-8] INFO - [pool-2-thread-6],干活好累21:11:49.991 [myPool-1] INFO - [pool-2-thread-3],干活好累21:11:49.991 [myPool-2] INFO - [pool-2-thread-9],干活好累21:11:49.991 [myPool-9] INFO - [pool-2-thread-10],干活好累21:11:49.991 [myPool-7] INFO - [pool-2-thread-1],干活好累21:11:49.991 [myPool-6] INFO - [pool-2-thread-4],干活好累21:11:49.991 [myPool-0] INFO - [pool-2-thread-8],干活好累21:11:50.091 [myPool-7] INFO - [pool-2-thread-1],终于干完了21:11:50.091 [myPool-4] INFO - [pool-2-thread-7],终于干完了21:11:50.091 [myPool-5] INFO - [pool-2-thread-5],终于干完了21:11:50.091 [myPool-2] INFO - [pool-2-thread-9],终于干完了21:11:50.091 [myPool-0] INFO - [pool-2-thread-8],终于干完了21:11:50.091 [myPool-1] INFO - [pool-2-thread-3],终于干完了21:11:50.091 [myPool-8] INFO - [pool-2-thread-6],终于干完了21:11:50.091 [myPool-6] INFO - [pool-2-thread-4],终于干完了21:11:50.091 [myPool-3] INFO - [pool-2-thread-2],终于干完了21:11:50.091 [myPool-9] INFO - [pool-2-thread-10],终于干完了
例子5
int loop = 2000;
for (int i = 0; i < loop; i++) {ThreadPoolUtils.execute(() -> {logger.info("干活好累");try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}logger.info("终于干完了");});}logger.info("不用等他,我们先干");// 控制台打印:............21:13:25.083 [myPool-19] INFO - 干活好累21:13:25.083 [myPool-8] INFO - 干活好累21:13:25.083 [myPool-30] INFO - 干活好累21:13:25.085 [main] WARN - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:100021:13:25.085 [main] WARN - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:100021:13:25.085 [main] WARN - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:100021:13:25.085 [main] WARN - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:100021:13:25.106 [myPool-7] INFO - 干活好累21:13:25.106 [myPool-11] INFO - 干活好累21:13:25.106 [main] WARN - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:100021:13:25.106 [myPool-6] INFO - 干活好累21:13:25.106 [myPool-4] INFO - 干活好累21:13:25.106 [main] WARN - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:100021:13:25.106 [main] WARN - 线程爆炸了,当前运行线程总数:33,活动线程数:33。等待队列已满,等待运行任务数:1000............
相关文章:
线程池工具类
线程池简述 为什么需要一个线程池工具类? 答:整个项目,用到线程执行任务的地方很多,不可能哪里用到就在那里直接new一个线程执行,这样资源得不到重复利用,一旦线程过多就会导致内存不足。 线程池的好处是…...

印尼“支付宝” DANA 如何借力 OceanBase 实现3个“关键零”
当前,移动支付在东南亚正迅猛发展,据谷歌、淡马锡与贝恩公司发布的报告预测,东盟地区蓬勃兴起的移动支付市场有望在2030年突破至2万亿美元的交易规模。 在此背景下,DANA作为印尼——东南亚最大经济体中的一员,秉持着推…...

2018-2022 年份微博签到数据集
前阵子接到一个实验室老师的需求,采集五年前(2024-52019)过年前后的北京微博签到数据。 前两年采集的深圳签到数据是 2022 年是当年的尚可,这次虽然时间跨度只有两个月,但是由于时间太过久远,但是颇费了一…...

Avalonia开发实践(二)——开发带边框的Grid
一、开发背景 在实际开发工作中,常常会用到Grid进行布局。为了美观考虑,会给每个格子加上边框,如下图: 原生的Grid虽然有ShowGridLines属性可以控制显示格子之间的线,但线的样式不能定义,可以说此功能非常…...

Java泛型的定义与运用
泛型 泛型的作用从使用层面上来说是统一数据类型,防止将来的数据转换异常。从定义层面上来说,定义带泛型的类,方法等,将来使用的时候给泛型确定什么类型,泛型就会变成什么类型,凡是涉及到泛型的都会变成确…...

Java如何自定义注解及在SpringBoot中的应用
注解 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说…...
微软 Edge 浏览器全解析
微软 Edge 是微软推出的一个现代化浏览器,继承了 Internet Explorer(IE)的部分功能,但在速度、安全性和兼容性方面做出了很大改进。下面是对微软 Edge 浏览器的详细解析,包括其特点、安装、配置和常见问题的解答。 微软 Edge 浏览器的特点 基于 Chromium 内核 Edge 浏览…...

C++ 八股(1)
C语言中strcpy为什么不安全?如何解决? 主要原因是缺乏对输入长度的边界检查,容易导致缓冲区溢出漏洞。 解决:可以使用strncpy函数替代,或者在程序最顶端加入代码段 #define _CRT_SECURE_NO_WARNINGS 缓冲区溢出 …...

超高精电容传感器PCAP01调试+LABVIEW数据可视化调试手记
PCAP01超高精电容传感芯片STM32LabView可视化 文章目录 PCAP01超高精电容传感芯片STM32LabView可视化一、PCAP01介绍1.1、PCAP01引脚定义1.2、电容测量1.3、温度测量1.4、PCAP典型测试电路 二、PCAP01的STM32驱动2.1、SPI协议配置2.2、PCAP01浮空电容测量内部温度测量操作流程 …...

5.更多
发现一个项目与 MkDocs 类似的项目 PyMdown 拓展文档 ,等待探索。 1.排版模仿 以下网站使用 MkDocs 构建 Material for MkDocs 的美化 - Charles Les Notebook (charleschile.com) Documentation - Home Assistant (home-assistant.io) Godot Docs – master bra…...
ConditionalOnJndi注解使用介绍、应用场景以及示例代码
概述 ConditionalOnJndi 是 Spring Framework 中的一个条件注解,用于在特定的 JNDI (Java Naming and Directory Interface) 环境条件下决定是否创建一个 bean 或配置一个 bean。JNDI 是 Java EE 规范中定义的一种用于访问命名和目录服务的 API,它允许 …...

Spring Cloud 引入
1.单体架构: 定义:所有的功能实现都打包成一个项目 带来的后果: ①后端服务器的压力越来越大,负载越来越高,甚至出现无法访问的情况 ②业务越来越复杂,为了满足用户的需求,单体应用也会越来越…...

自定义波形图View,LayoutInflater动态加载控件保存为本地图片
效果图: 页面布局: <?xml version"1.0" encoding"utf-8"?><LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:la…...
每日一道算法题 求最小公倍数
题目 求最小公倍数_牛客题霸_牛客网 (nowcoder.com) Python 辗转相除法 dividend,divisormap(int,input().split()) #被除数,除数 # remainder0 余数 # 最小公倍数 def lcm(dividend,divisor):# 最大公约数def gcd(dividend,divisor):if 0divisor:return divid…...
【OCC学习18】三维几何对象工具包:TKG3d
【OCC学习18】三维几何对象工具包:TKG3d loveoobaby 已于 2022-08-26 10:10:32 修改 阅读量1.2k 收藏 10 点赞数 1 分类专栏: OpenCascade学习笔记 文章标签: 学习 版权 OpenCascade学习笔记 专栏收录该内容 24 篇文章60 订阅 订阅专栏…...
【Unix】SunOS/Oracle Solaris系统介绍
一.SunOS系统介绍 SunOS 是由 Sun Microsystems 开发的 Unix 操作系统。它最初是为 Sun 的 SPARC 架构计算机设计的,后来也支持了 Intel x86 架构。SunOS 是基于 UNIX System V 4.1 版本,并且随着时间的发展,SunOS 经历了多个版本迭代&#…...

氛围感视频素材高级感的去哪里找啊?带氛围感的素材网站库分享
亲爱的创作者们,大家好!今天我们来聊聊视频创作中至关重要的一点——氛围感。一个好的视频,不仅要有视觉冲击力,还要能够触动观众的情感。那我们应该去哪里寻找这些充满氛围感且高级的视频素材呢?别急,我这…...

基于Java的学生选课系统
第1章 系统概述 1.1概述 背景:随着计算机网络技术的发展,Web 数据库技术已成为应用最为广泛的网站架构基础技术。学生选课系统作为教育单位不可缺少的部分,其内容对于学校的决策者和管理者至关重要。传统的人工管理方式存在效率低、保密性差等…...

802.11漫游流程简单解析与笔记_Part2_05_wpa_supplicant如何通过nl80211控制内核开始关联
最近在进行和802.11漫游有关的工作,需要对wpa_supplicant认证流程和漫游过程有更多的了解,所以通过阅读论文等方式,记录整理漫游相关知识。Part1将记录802.11漫游的基本流程、802.11R的基本流程、与认证和漫游都有关的三层秘钥基础。Part1将包…...

STM32的 DMA(直接存储器访问) 详解
STM32的DMA(Direct Memory Access,直接存储器存取)是一种在单片机中用于高效实现数据传输的技术。它允许外设设备直接访问RAM,不需要CPU的干预,从而释放CPU资源,提高CPU工作效率,本文基于STM32F…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...