线程池一定需要了解的那些事

一、阿里Java开发规范,为啥禁止直接使用Executors创建线程池

  •  newFixdThreadPool 及 singleThreadPool 中默认队列长度为 Integer.MAX_VALUE,如果线程执行比较耗时,执行任务的线程在队列中产生大量堆积,进而有导致虚拟机OOM 的风险。
  public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}//默认长度 Integer.MAX_VALUEpublic LinkedBlockingQueue() {this(Integer.MAX_VALUE);}
  • newCachedThreadPool 允许创建最大线程数量为 Integer.MAX_VALUE,当大量任务需要执行时,可能会导致大量线程的创建,每个线程默认占1M,线程占据资源过多或队列中线程产生堆积,导致 CPU 过高或 java虚拟机 OOM 的问题 。
   // 最大线程数 默认为:Integer.MAX_VALUEpublic static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}
  • 使用ThreadPoolExecutor 来构造线程池, 建议明确指定线程池的核心参数:最小线程数、最大线程数,队列长度、拒绝策略等等,确保线程池运稳定运行。

二、如何合理配置线程池的大小

  •  CPU 密集型: 主要执行计算任务,响应时间较快,任务 cpu 的利用率很高。线程数的配置由服务器 CPU 核心数来决定, 建议CPU 核心数=同时最大执行线程数,如 CPU 核心数为 8,表明服务器最多能同时执行 8个线程。创建过多的线程反而会导致线程之间上下文切换,降低执行效率。推荐:线程池的最大线程数= cpu 核心数+1。
  •  IO 密集型: 主要进行 IO 操作,执行 IO 操作(文件读写、网络通信等)相对比较耗时,cpu相对处于空闲状态, 导致 cpu 的利用率不高,建议可以增加线程的数量。IO密集型操作建议结合线程的等待时长来做判断,等待时间越长,线程数相对配置的越多。一般建议配置 cpu 核心数的 2 倍。 基础公式:线程池设定最佳线程数目 = ((线程池配置的线程等待时间+线程 CPU 时间)/ 线程 CPU 时间 )* CPU 数目 。公式中线程 cpu等待时间是计算出程序中单个线程在 cpu 上运行的时间。

三、线程池中的线程的初始化

         线程池创建后,线程池默认没有初始化,简而言之就是线程池中没有线程,在提交任务之后才会创建线程。 在并发系统中,为提高系统的吞吐量,建议在线程池创建之后立即创建线程。通过以下两个方法可以实现线程的初始化:

        ExecutorService executorService = new ThreadPoolExecutor(10,20,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());ThreadPoolExecutor threadPoolExecutor=(ThreadPoolExecutor)executorService;//方式1 初始化所有核心线程threadPoolExecutor.prestartAllCoreThreads();//方式2 初始化一个核心线程threadPoolExecutor.prestartCoreThread();

四、线程池的关闭

  • shutdown():不会立即终止线程池,等所有任务队列中的任务都执行完后才终止,同时也不会接受新的任务 。
  • shutdownNow():立即终止线程池,并尝试打断正在执行的任务且清空任务队列,返回未执行的任务。

五、线程池核心参数支持动态调整及线程池监控

  • setCorePoolSize:设置核心线程数
    public void setCorePoolSize(int corePoolSize) {if (corePoolSize < 0)throw new IllegalArgumentException();int delta = corePoolSize - this.corePoolSize;this.corePoolSize = corePoolSize;if (workerCountOf(ctl.get()) > corePoolSize)interruptIdleWorkers();else if (delta > 0) {// We don't really know how many new threads are "needed".// As a heuristic, prestart enough new workers (up to new// core size) to handle the current number of tasks in// queue, but stop if queue becomes empty while doing so.int k = Math.min(delta, workQueue.size());while (k-- > 0 && addWorker(null, true)) {if (workQueue.isEmpty())break;}}}
  • setMaximumPoolSize:设置线程池最大线程数目
   public void setMaximumPoolSize(int maximumPoolSize) {if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)throw new IllegalArgumentException();this.maximumPoolSize = maximumPoolSize;if (workerCountOf(ctl.get()) > maximumPoolSize)interruptIdleWorkers();}
  • beforeExecute:  获取执行之前的核心参数
  • afterExecute:  获取执行之后的核心参数

    protected void beforeExecute(Thread t, Runnable r) {BlockingQueue<Runnable> blockingQueue = getQueue();log.info("执行前! 线程池名称:{},初始线程数:{},核心线程数:{},活跃的任务数量:{},已经执行的任务数:{},任务总数:{},允许最大的线程数:{}," +"线程允许空闲时间:{},队列的容量:{}",name,getPoolSize(),getCorePoolSize(),getActiveCount(),getCompletedTaskCount(),getTaskCount(),getMaximumPoolSize(),getKeepAliveTime(TimeUnit.MILLISECONDS),(blockingQueue.size() + blockingQueue.remainingCapacity()));}/*** @description: 线程监控使用* @param: r* @param: t* @return: void* @author: * @date: 2022/1/17 16:58*/protected void afterExecute(Runnable r, Throwable t) {BlockingQueue<Runnable> blockingQueue = getQueue();log.info("执行后! 线程池名称:{},初始线程数:{},核心线程数:{},活跃的任务数量:{},已经执行的任务数:{},任务总数:{},允许最大的线程数:{}," +"线程允许空闲时间:{},队列的容量:{}",name,getPoolSize(),getCorePoolSize(),getActiveCount(),getCompletedTaskCount(),getTaskCount(),getMaximumPoolSize(),getKeepAliveTime(TimeUnit.MILLISECONDS),(blockingQueue.size() + blockingQueue.remainingCapacity()));}

六、推荐开源线程池监控 Hippo4j

  • 动态可观测线程池框架,为业务系统提高线上运行保障能力

 

 

 官网:Hippo4j | Hippo4j

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

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

相关文章

Numpy学习笔记

科学计算库&#xff08;Numpy&#xff09; 通常数据都能转换成矩阵&#xff0c;行就是每一条样本数据&#xff0c;列就是每个字段的特征&#xff0c;Numpy在矩阵运算上非常高效&#xff0c;可以快速处理数据并进行数据计算。 Numpy基本操作 先导入 import numpy as nparray…

【C语言】位段,枚举和联合体详解

目录 1.位段 1.1 什么是位段 1.2 位段的内存分配 1.3 位段的跨平台问题 2.枚举 2.1 枚举类型的定义 2.2 枚举的优点 3. 联合&#xff08;共用体&#xff09; 3.1 联合类型的定义 3.2 联合的特点 3.3 联合大小的计算 1.位段 1.1 什么是位段 位段的声明和结构体是类…

EureKa快速入门

EureKa快速入门 远程调用的问题 多个服务有多个端口&#xff0c;这样的话服务有多个&#xff0c;硬编码不太适合 eureKa的作用 将service的所有服务的端口全部记录下来 想要的话 直接从注册中心查询对于所有服务 每隔一段时间需要想eureKa发送请求 保证服务还存活 动手实践 …

element表格多选实现

表格实现多选 实现表格多选很简单&#xff0c;只需要在表格里加上一列即可&#xff0c;加完之后就会在表格里出现一列白色的四方块按钮&#xff0c;可以多选&#xff0c;也可以单选 <el-table-columntype"selection"width"55"align"center"&…

17.2 【Linux】通过 systemctl 管理服务

systemd这个启动服务的机制&#xff0c;是通过一支名为systemctl的指令来处理的。跟以前 systemV 需要 service / chkconfig / setup / init 等指令来协助不同&#xff0c; systemd 就是仅有systemctl 这个指令来处理而已。 17.2.1 通过 systemctl 管理单一服务 &#xff08;s…

Wireshark数据抓包分析之HTTP协议

一、实验目的&#xff1a; 主要时熟悉wireshark的使用 二、预备知识&#xff1a; HTTP协议的相关知识 what fk&#xff0c;原来只要在右页点击切换&#xff0c;就可以开启2台不同的机器欸&#xff01;nice 三、实验过程&#xff1a; 1.在机器1中通过管理员身份运行hfs之后&a…

Struts vs. Struts 2:Java Web 开发框架的升级之路与竞争力分析

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

centos如何查找某一命令对应的安装包

需求背景 有时候在容器里搭建了一个开发环境&#xff0c;需要有些命令能在容器里也能用&#xff0c;但是有时候只知道命令&#xff0c;但是不知道这个命令对应的是哪个安装包提供&#xff0c;比如最简单的命令 ip命令&#xff0c;"ip a"可以查看主机的所有ip信息&am…

多客户企业选择拥有哪些功能的CRM系统?

管理海量客户信息对于每一家企业都是巨大的挑战。粗放式的管理客户资料是对资源的一种浪费&#xff0c;让很多有意向的高价值客户流失。客户比较多&#xff0c;有什么CRM系统推荐吗&#xff1f;帮助企业轻松地跟进客户&#xff0c;提高销售效率&#xff1f; 1.易于使用 首先是…

【ES6】—【必备知识】—箭头函数

一、定义函数 1. ES5 1. 普通函数预定义&#xff0c;再调用 console.log(sum(1, 2)) function sum (x, y) {return x y } console.log(sum(1, 2))2. 函数表达式 按代码顺序定义 console.log(sum(1, 2)) // sum is not a function // sum不是一个函数 var sum function (x…

opencv-yolov8-目标检测

import cv2 from ultralytics import YOLO# 模型加载权重model YOLO(yolov8n.pt)# 视频路径cap cv2.VideoCapture(0)# 对视频中检测到目标画框标出来 while cap.isOpened():# Read a frame from the videosuccess, frame cap.read()if success:# Run YOLOv8 inference on th…

Temu闯关日韩受挫?跨境电商卖家如何打磨好营销链路

海外版拼多多 Temu 先后在日本和韩国上线&#xff0c;然而效果不似预期&#xff0c;日韩市场对这套“低价补贴”策略并不买账。作为一个尚未被日韩消费者熟悉的网站&#xff0c;其价格之便宜无法让消费者信任。除此之外更大的问题是&#xff0c;在日本卷不过线下零售与百元店&a…

怎么去选消息队列? Kafka vs. RabbitMQ

在上周&#xff0c;我们讨论了使用消息队列的好处。然后我们回顾了消息队列产品的发展历史。如今&#xff0c;在项目中需要使用消息队列时&#xff0c;Apache Kafka似乎是首选产品。然而&#xff0c;考虑到特定需求时&#xff0c;它并不总是最佳选择。 基于数据库的队列 让我们…

springboot引入druid解析sql

一、前言 在开发中&#xff0c;有时我们可能会需要获取SQL中的表名&#xff0c;那么因为不同的数据源类型SQL会存在部分差异&#xff0c;那么我们就可以使用alibaba 的druid包实现不同的数据源类型的sql解析。 二、引入相关maven依赖 <dependency><groupId>com.a…

【核磁共振成像】傅里叶重建

目录 一、傅里叶重建二、填零三、移相四、数据窗函数五、矩形视野六、多线圈数据重建七、图像变形校正八、缩放比例九、基线校准 长TR&#xff0c;长TE&#xff0c;是T2加权像&#xff1b; 短TR&#xff0c;短TE&#xff0c;是T1加权像&#xff1b; 长TR&#xff0c;短TE&#…

Debootstrap 教程

文章目录 Debootstrap 教程安装 debootstrap使用 debootstrap运行 debootstrap进入新的系统结束语 Debootstrap 教程 debootstrap 是一个用于在 Debian-based 系统上创建一个基本的 Debian 系统的工具。它可以用于创建 chroot 环境、容器或者为新的系统安装做准备。 安装 deb…

oracle警告日志\跟踪日志磁盘空间清理

oracle警告日志\跟踪日志磁盘空间清理 问题现象&#xff1a; 通过查看排查到alert和tarce占用大量磁盘空间 警告日志 /u01/app/oracle/diag/rdbms/orcl/orcl/alert 跟踪日志 /u01/app/oracle/diag/rdbms/orcl/orcl/trace 解决方案&#xff1a; 用adrci清除日志 确定目…

item_search_img-按图搜索淘宝商品(拍立淘)

一、接口参数说明&#xff1a; item_search_img-按图搜索淘宝商品&#xff08;拍立淘&#xff09;&#xff0c;点击更多API调试&#xff0c;请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/taobao/item_search_img 名称类型必须描…

OpenAI推出GPT-3.5Turbo微调功能并更新API;Midjourney更新局部绘制功能

&#x1f989; AI新闻 &#x1f680; OpenAI推出GPT-3.5Turbo微调功能并更新API&#xff0c;将提供GPT-4微调功能 摘要&#xff1a;OpenAI宣布推出GPT-3.5Turbo微调功能&#xff0c;并更新API&#xff0c;使企业和开发者能够定制ChatGPT&#xff0c;达到或超过GPT-4的能力。通…

Ribbon 源码分析

Ribbon 源码分析 Ribbon Debug 分析 断点 LoadBalancerInterceptor LoadBalancerInterceptor 实现了 ClientHttpRequestInterceptor 接口&#xff0c;重写了其中的 intercept 方法&#xff0c;用来拦截请求&#xff1b; 获取原始的 uri 和 服务名&#xff0c;调用 LoadBalanc…