线程调优——调整线程池参数提升程序执行效率

        先抛出一个问题,程序开发真的是线程越多效率越高吗?多线程是我们程序开发中必不可少的手段,线程就像“孙悟空”开启了分身术一样,每个分身都在“打妖怪”,那是不是分身越多,“打妖怪”的效率就越高?

文章目录

    • 一、前言
    • 二、演示实例
    • 三、执行结果
    • 四、结论分析

一、前言

        其实,线程的数量并不是越多越好,每个线程都需要系统分配一定的资源,如内存和CPU时间。每个线程都有其栈内存,线程数量过多可能导致内存不足,甚至可能影响系统的稳定性。线程的管理和使用需要根据具体的应用场景和需求来决定,通常,线程数量应与可用的CPU核心数相匹配,或者稍微多一些,以充分利用多核处理器的能力。如果线程数量超过了CPU核心数,线程间的上下文切换会变得频繁,可能会导致性能下降。
        一般情况下,根据业务的需求及服务器的配置,调整最优的线程池参数来进行线程调优,提升程序的执行效率。说线程池调优之前,先说下线程池的4个重要参数,分别是:corePoolSize(核心线程数)、maximumPoolSize(最大线程数)、workQueue(队列容量)、keepAliveTime(非核心回收超时时间)。

corePoolSize:是线程池中保持活动状态的线程的最小数量,即使这些线程在空闲时也不会被终止。

maximumPoolSize:是线程池能够容纳的最大线程数量,限制线程池中线程的最大数量,防止过多线程的创建,避免资源耗尽和系统过载。

workQueue:是一个阻塞队列,用于存储待执行的任务。

keepAliveTime:线程存活时间,是线程池中多余线程(即除过corePoolSize之外的线程)在空闲时保持活动的最大时间。如果线程在此时间内没有被使用,则会被终止。

以下通过一个demo来演示下线程池中实际参与工作的线程数!

二、演示实例

我们初始化的参数分别是corePoolSize=10、maximumPoolSize=30、workQueue=50,然后依次模拟5、10、15、45、60、65、75、80、81的任务数,下面的演示模拟的代码:

	public static void main(String[] args) {// 模拟任务数int taskCount = 75;// 使用AtomicInteger线程安全的计数器,支持在多线程环境中安全地增减值而不需要使用锁AtomicInteger integer = new AtomicInteger();// 定义一个时间区间集合,存储各个任务执行到时的耗时(单位:毫秒)情况List<Long> diffList = new ArrayList<>();// 初始化线程池,核心参数如下ThreadPoolExecutor executor = new ThreadPoolExecutor(10, // 核心线程数30, // 最大线程数5, // 非核心回收超时时间TimeUnit.SECONDS, // 超时时间单位new ArrayBlockingQueue<>(50));  // 任务队列// 记录当前时间戳long start = System.currentTimeMillis();// 模拟程序任务for (int i = 0; i < taskCount; i++) {Thread thread = new Thread(() -> {try {// 模拟执行耗时1秒Thread.sleep(1000);// 自增步进1并返回新值int j = integer.addAndGet(1);// 当前任务耗时记录long l = System.currentTimeMillis() - start;System.out.println("已执行" + j + "个任务,耗时" + l + "ms");// 把耗时记录存储到集合中diffList.add(l);} catch (InterruptedException e) {e.printStackTrace();}});// 把线程放到线程池中try {executor.execute(thread);} catch (Exception e) {e.printStackTrace();}}// 验证程序执行结束,并记录结束时间戳long end = 0;while (executor.getCompletedTaskCount() < taskCount) {end = System.currentTimeMillis();}System.out.println("总任务数:"+taskCount);/*** 1.把集合中所有时间区间的值都除以1000,这样的话,集合中的值就只会出现整型的1、2、3...,用于标识任务属于哪个批次(刚好1秒一个批次)* 2.然后把集合聚合分组整理成HashMap,方便我们统计各个批次的数量* 3.然后打印出来*/Map<Long, List<Long>> collect = diffList.stream().map(i -> i / 1000).collect(Collectors.groupingBy(i -> i.longValue()));for (Long l : collect.keySet()) {System.out.println("第【"+l+"】批次,工作线程数:"+collect.get(l).size());}System.out.println("任务总耗时:" + (end - start) + "ms");}

三、执行结果

为了方便对比查看,我把每次的执行结果都贴到一起了,如下:

总任务数:5
第【1】批次,工作线程数:5
任务总耗时:1074ms
-----------------------------------------
总任务数:10
第【1】批次,工作线程数:10
任务总耗时:1069ms
-----------------------------------------
总任务数:15
第【1】批次,工作线程数:10
第【2】批次,工作线程数:5
任务总耗时:2068ms
-----------------------------------------
总任务数:45
第【1】批次,工作线程数:10
第【2】批次,工作线程数:10
第【3】批次,工作线程数:10
第【4】批次,工作线程数:10
第【5】批次,工作线程数:5
任务总耗时:5117ms
-----------------------------------------
总任务数:60
第【1】批次,工作线程数:10
第【2】批次,工作线程数:10
第【3】批次,工作线程数:10
第【4】批次,工作线程数:10
第【5】批次,工作线程数:10
第【6】批次,工作线程数:10
任务总耗时:6151ms
-----------------------------------------
总任务数:65
第【1】批次,工作线程数:15
第【2】批次,工作线程数:15
第【3】批次,工作线程数:15
第【4】批次,工作线程数:15
第【5】批次,工作线程数:5
任务总耗时:5128ms
-----------------------------------------
总任务数:75
第【1】批次,工作线程数:25
第【2】批次,工作线程数:25
第【3】批次,工作线程数:25
任务总耗时:3079ms
-----------------------------------------
总任务数:80
第【1】批次,工作线程数:30
第【2】批次,工作线程数:30
第【3】批次,工作线程数:20
任务总耗时:3079ms
-----------------------------------------
总任务数:81
java.util.concurrent.RejectedExecutionException: Task Thread[Thread-80,5,main] rejected from java.util.concurrent.ThreadPoolExecutor@6b143ee9[Running, pool size = 30, active threads = 30, queued tasks = 50, completed tasks = 0]
-----------------------------------------

四、结论分析

根据上述结果分析,可以得到如下结论:

数量关系工作线程数 task示例
场景1 taskCount <= corePoolSize taskCount 5、10
场景2 corePoolSize < taskCount <= corePoolSize+workQueue corePoolSize 15、45、60
场景3 corePoolSize+workQueue < taskCount <= maximumPoolSize+workQueue taskCount-workQueue 65、75、80
场景4 taskCount > maximumPoolSize+workQueue 小于的部分正常执行,大于的部分会拒绝策略,在线程池中抛出异常 81
字段说明 corePoolSize(核心线程数)、maximumPoolSize(最大线程数)、workQueue(队列容量)、taskCount(任务数)

        所以,不一定任务数量少就耗时少,也不一定任务数量多就耗时长,因为不同任务下线程池分配的工作线程数是不一样的。合理地调配资源和参数,在充分利用服务器资源的同时,可以达到程序执行的最优状态!

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

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

相关文章

Redisson实现分布式锁(看门狗机制)

目录 可重入锁&#xff1a; 锁重试和看门狗机制&#xff1a; 主从一致性&#xff1a; 首先引入依赖&#xff0c;配置好信息 3.使用Redisson的分布式锁 可重入锁&#xff1a; 可重入锁实现是通过redsi中的hash实现的&#xff0c;key依旧是业务名称加id&#xff0c;然后第一个…

如何成立一家自己的等级保护测评机构?需要哪些条件?有哪些要求?

给大家的福利&#xff0c;点击下方蓝色字 即可免费领取↓↓↓ &#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 前言 各省、自治区、直辖市公安厅、局网络安全保卫总队&#xff0c;新疆生产建设兵团公安局网络安…

【高分系列卫星简介——高分一号(GF-1)】

高分一号卫星&#xff08;GF-1&#xff09; 高分一号&#xff08;GF-1&#xff09;是中国高分辨率对地观测系统&#xff08;简称“高分专项”&#xff09;的第一颗卫星&#xff0c;具有里程碑式的意义。以下是对高分一号卫星的详细介绍&#xff1a; 一、基本信息 发射时间&…

2024华为杯研究生数学建模竞赛(研赛)选题建议+初步分析

提示&#xff1a;C君认为的难度&#xff1a;DE<C<F&#xff0c;开放度&#xff1a;CDE>F。 华为专项的题目&#xff08;A、B题&#xff09;暂不进行选题分析&#xff0c;不太建议大多数同学选择&#xff0c;对自己专业技能有很大自信的可以选择华为专项的题目。后续会…

MyBatis-config.xml核心配置

MyBatis-config.xml 包含了会深深影响MyBatis行为的设置和属性信息&#xff0c;配置文档的顶层结构如下 environments&#xff08;环境配置&#xff09; environments用于配置数据库的URL信息&#xff0c;MyBatis-config可以动态配置多个数据源&#xff0c;用于连生产、预发、…

用 HTML + JavaScript DIY 一个渐进式延迟法定退休年龄测算器

为减轻社会和个人因退休年龄变化带来的冲击&#xff0c;近日&#xff0c;全国人民代表大会常务委员会正式发布了关于实施渐进式延迟法定退休年龄的重要决定。 根据该决定&#xff0c;我国将同步启动对男、女职工法定退休年龄的延迟计划。这一调整将采取渐进式的方式进行&#…

RabbitMQ 高级特性——发送方确认

文章目录 前言发送方确认confirm 确认模式return 退回模式 常见面试题 前言 前面我们学习了 RabbitMQ 中交换机、队列和消息的持久化&#xff0c;这样能够保证存储在 RabbitMQ Broker 中的交换机和队列中的消息实现持久化&#xff0c;就算 RabbitMQ 服务发生了重启或者是宕机&…

Nginx实用篇:实现负载均衡、限流与动静分离

Nginx实用篇&#xff1a;实现负载均衡、限流与动静分离 | 原创作者/编辑&#xff1a;凯哥Java | 分类&#xff1a;Nginx学习系列教程 Nginx 作为一款高性能的 HTTP 服务器及反向代理解决方案&#xff0c;在互联网架构中扮演着至关重要的角色。它…

Acwing DFS

DFS&#xff1a;深度优先搜索 DFS与BFS的对比 DFS使用栈来实现&#xff0c;BFS使用队列来实现 DFS所需要的空间是 O ( h ) O(h) O(h),而BFS需要的空间是 O ( 2 h ) O(2^h) O(2h),其中h是树的高度&#xff1b; DFS不具有最短路的特性&#xff0c;BFS有最短路的特性 DFS回溯…

102.SAPUI5 sap.ndc.BarcodeScannerButton调用摄像头时,localhost访问正常,使用IP访问失败

目录 原因 解决办法 1.修改谷歌浏览器的setting 2.在tomcat中配置https访问 参考 使用SAPUI5的sap.ndc.BarcodeScannerButton调用摄像头时&#xff0c;localhost访问正常&#xff0c;使用IP访问时&#xff0c;一直打不开摄像头&#xff0c;提示getUserMedia()问题。 原因…

2024 “华为杯” 中国研究生数学建模竞赛(D题)深度剖析|大数据驱动的地理综合问题|数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题&#xff01; CS团队倾注了大量时间和心血&#xff0c;深入挖掘解…

elasticsearch同步mysql方案

文章目录 1、1. 使用数据库触发器2. 使用定时任务3. 监听MySQL二进制日志&#xff08;binlog&#xff09;4. 使用数据管道5. 使用第三方工具或服务6. 编写自定义脚本注意事项 2、1. 使用Logstash步骤&#xff1a;示例配置&#xff1a; 2. 使用Debezium步骤&#xff1a; 3. 自定…

828华为云征文 | 解锁企业级邮件服务,在华为云fFlexus x实例上部署Mailcow开源方案

前言 华为云Flexus X实例携手Mailcow开源邮件方案&#xff0c;为企业打造了一个既高效又安全的邮件服务解决方案。Flexus X实例的柔性算力与高性能&#xff0c;是这一方案的坚实基石。它提供CPU内存的灵活定义&#xff0c;以经济型价格实现旗舰级性能&#xff0c;确保邮件服务的…

云计算课程作业1

作业1 Xmanager连接 rhel连接 作业2 首先确认你的虚拟机设置的是NAT 1-3 然后打开这篇blog&#xff0c;并完成第一步和第二步 因为我们是NAT&#xff0c;所以不需要连接网桥&#xff0c;即跳过第三步&#xff0c;但是这里ping一下测试网络连接 2- 如果到这里你发现提示yum…

Stylized Smooth Clouds 卡通风格化云朵包

下载:​​Unity资源商店链接资源下载链接 效果图:

828华为云征文|Flexus X实例Docker+Jenkins+gitee实现CI/CD自动化部署-解放你的双手~

目录 前言 实验步骤 环境准备 安装Portainer 拉取镜像 更换镜像源 启动容器 安装jenkins 拉取镜像 获取管理员密码 新建流水线项目 Portainer配置 gitee配置WebHooks 构建 修改代码&#xff0c;自动部署 前言 &#x1f680; 828 B2B企业节特惠来袭&#xff0c;…

如何通过蜂巢(容器安全)管理内部部署数据安全产品与云数据安全产品?

本文将探讨内部部署和云数据安全产品之间的主要区别。在思考这个问题之前&#xff0c;首先了解内部部署和云数据安全产品之间的主要区别。 内部部署数据安全产品意味着管理控制台位于企业客户的内部部署&#xff0c;而德迅云安全则在云中托管云数据安全产品。德迅云安全供应商通…

gin集成jaeger中间件实现链路追踪

1. 背景 新业务线带来新项目启动&#xff0c;需要改进原有项目的基础框架和组件能力&#xff0c;以提升后续开发和维护效率。项目搭建主要包括技术选型、框架搭建、基础服务搭建等。这其中就涉及到链路追踪的内容&#xff0c;结合其中的踩坑情况&#xff0c;用一篇文章来说明完…

【第十三章:Sentosa_DSML社区版-机器学习聚类】

目录 【第十三章&#xff1a;Sentosa_DSML社区版-机器学习聚类】 13.1 KMeans聚类 13.2 二分KMeans聚类 13.3 高斯混合聚类 13.4 模糊C均值聚类 13.5 Canopy聚类 13.6 Canopy-KMeans聚类 13.7 文档主题生成模型聚类 13.8 谱聚类 【第十三章&#xff1a;Sentosa_DSML社…

54.【C语言】 字符函数和字符串函数(strncpy,strncat,strncmp函数)

和strcpy,strcat,strcmp函数对应的是strncpy,strncat,strncmp函数 8.strncpy函数 *简单使用 cplusplus的介绍 点我跳转 翻译: 函数 strncpy char * strncpy ( char * destination, const char * source, size_t num ); 从字符串中复制一些字符 复制源(source)字符串的前num个…