工作中何如来合理分配核心线程数?

news2025/2/24 22:16:49


文章目录

  • 一 回顾
    • 1.1 使用线程池的优点
    • 1.2 任务类型
    • 1.3 IO密集型任务确定线程数
    • 1.4 CPU密集型任务确定线程数
    • 1.5 混合型任务确定线程数

一 回顾

1.1 使用线程池的优点

  • 降低资源消耗:线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,通过重复利用已创建的线程可以降低线程创建和销毁造成的消耗。
  • 提高响应速度:当任务到达时,可以不需要等待线程创建就能立即执行。
  • 提高线程的可管理性:线程池提供了一种限制、管理资源的策略,维护一些基本的线程统计信息,如已完成任务的数量等。通过线程池可以对线程资源进行统一的分配、监控和调优。

注意:但是在生产环境中,不合理的分配线程数,可能会造成严重的生成事故

1.2 任务类型

  1. IO密集型任务此类任务主要是执行IO操作。由于执行IO操作的时间较长,导致CPU的利用率不高,这类任务CPU常处于空闲状态。Netty的IO读写操作为此类任务的典型例子。
  2. CPU密集型任务此类任务主要是执行计算任务。由于响应时间很快,CPU一直在运行,这种任务CPU的利用率很高。
  3. 混合型任务此类任务既要执行逻辑计算,又要进行IO操作(如RPC调用、数据库访问)。相对来说,由于执行IO操作的耗时较长(一次网络往返往往在数百毫秒级别),这类任务的CPU利用率也不是太高。Web服务器的HTTP请求处理操作为此类任务的典型例子。

1.3 IO密集型任务确定线程数

  • 由于IO密集型任务的CPU使用率较低,导致线程空余时间很多,因此通常需要开CPU核心数两倍的线程。
  • 当IO线程空闲时,可以启用其他线程继续使用CPU,以提高CPU的使用率。

Netty 核心线程数

     //多线程版本Reactor实现类
     public abstract class MultithreadEventLoopGroup extends
             MultithreadEventExecutorGroup implements EventLoopGroup {
     
         //IO事件处理线程数
         private static final int DEFAULT_EVENT_LOOP_THREADS;
     
         //IO事件处理线程数默认值为CPU核数的两倍
         static {
             DEFAULT_EVENT_LOOP_THREADS = Math.max(1,
                      SystemPropertyUtil.getInt("io.netty.eventLoopThreads",
                      Runtime.getRuntime().availableProcessors() * 2));
         }
     
         /**
          *构造器
          */
         protected MultithreadEventLoopGroup(int nThreads, 
                     ThreadFactory threadFactory, Object... args) {
             super(nThreads == 0?
                      DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
         }
     }

总结

如果是IO密集型任务核心数=CPU核数的两倍

参考案例


     // 省略import
     public class ThreadUtil
     {
         //CPU核数
         private static final int CPU_COUNT =
                                         Runtime.getRuntime().availableProcessors();
         //IO处理线程数
         private static final int IO_MAX = Math.max(2, CPU_COUNT * 2);
         /**
          * 空闲保活时限,单位秒
          */
         private static final int KEEP_ALIVE_SECONDS = 30;
         /**
          * 有界队列size
          */
         private static final int QUEUE_SIZE = 128;
         //懒汉式单例创建线程池:用于IO密集型任务
         private static class IoIntenseTargetThreadPoolLazyHolder
         {
             //线程池: 用于IO密集型任务
             private static final ThreadPoolExecutor EXECUTOR =
                                                                new ThreadPoolExecutor(
                     IO_MAX,  //CPU核数*2
                     IO_MAX,  //CPU核数*2
                     KEEP_ALIVE_SECONDS,
                     TimeUnit.SECONDS,
                     new LinkedBlockingQueue(QUEUE_SIZE),
                     new CustomThreadFactory("io"));
     
             static
             {
                 EXECUTOR.allowCoreThreadTimeOut(true);
                 //JVM关闭时的钩子函数
                 Runtime.getRuntime().addShutdownHook(
                         new ShutdownHookThread("IO密集型任务线程池",
                                                                     new Callable<Void>()
                         {
                             @Override
                             public Void call() throws Exception
                             {
                                 //优雅地关闭线程池
                                 shutdownThreadPoolGracefully(EXECUTOR);
                                 return null;
                             }
                         }));
             }
         }
     }

1.4 CPU密集型任务确定线程数

CPU密集型任务也叫计算密集型任务,其特点是要进行大量计算而需要消耗CPU资源,比如计算圆周率、对视频进行高清解码等。CPU密集型任务虽然也可以并行完成,但是并行的任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以要最高效地利用CPU,CPU密集型任务并行执行的数量应当等于CPU的核心数。

案例

	// 省略import
     public class ThreadUtil
     {
         //CPU核数
         private static final int CPU_COUNT =
                                         Runtime.getRuntime().availableProcessors();
     
         private static final int MAXIMUM_POOL_SIZE = CPU_COUNT;
     
         //懒汉式单例创建线程池:用于CPU密集型任务
         private static class CpuIntenseTargetThreadPoolLazyHolder
         {
             //线程池:用于CPU密集型任务
             private static final ThreadPoolExecutor EXECUTOR = 
                                                               new ThreadPoolExecutor(
                     MAXIMUM_POOL_SIZE,
                     MAXIMUM_POOL_SIZE,
                     KEEP_ALIVE_SECONDS,
                     TimeUnit.SECONDS,
                     new LinkedBlockingQueue(QUEUE_SIZE),
                     new CustomThreadFactory("cpu"));
     
             static
             {
                 EXECUTOR.allowCoreThreadTimeOut(true);
                 //JVM关闭时的钩子函数
                 Runtime.getRuntime().addShutdownHook(
                         new ShutdownHookThread("CPU密集型任务线程池",
                                                                   new Callable<Void>()
                         {
                             @Override
                             public Void call() throws Exception
                             {
                                 //优雅地关闭线程池
                                 shutdownThreadPoolGracefully(EXECUTOR);
                                 return null;
                             }
                         }));
             }
         }
         // 省略不相干代码
     }

1.5 混合型任务确定线程数

混合型任务既要执行逻辑计算,又要进行大量非CPU耗时操作(如RPC调用、数据库访问、网络通信等),所以混合型任务CPU的利用率不是太高,非CPU耗时往往是CPU耗时的数倍。比如在Web应用中处理HTTP请求时,一次请求处理会包括DB操作、RPC操作、缓存操作等多种耗时操作。一般来说,一次Web请求的CPU计算耗时往往较少,大致在100~500毫秒,而其他耗时操作会占用500~1000毫秒,甚至更多的时间。

     最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1) * CPU核数

等待时间所占的比例越高,需要的线程就越多;CPU耗时所占的比例越高,需要的线程就越少。

获取所有线程的CPU执行时间

ThreadMXBean tmbean = ManagementFactory.getThreadMXBean();
tmbean.setThreadContentionMonitoringEnabled(true);
long[] allThread = tmbean.getAllThreadIds();

获取到id数组之后,遍历线程id,通过getThreadCpuTime(long id)等获取线时间

获取等待、阻塞时间等

ThreadInfo info = tmbean.getThreadInfo(threadId);
package Time;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

/**
 * @description:
 * @author: shu
 * @createDate: 2022/11/1 13:45
 * @version: 1.0
 */
public class TimeThreadTest {
    public static void main(String[] args) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean();
        bean.setThreadContentionMonitoringEnabled(true);
        long[] allThread = bean.getAllThreadIds();
        if (allThread.length > 0) {
            for (long threadId : allThread) {
                ThreadInfo info = bean.getThreadInfo(threadId);
                Long userTime = info.getWaitedTime();
                System.out.println("ThreadId:" + info.getThreadId() +" "+ "ThreadName:" + info.getThreadName() +"  "+ "ThreadState:" + info.getThreadState() +"  "+"userTime:" + userTime.toString());
            }
        }

    }
}

image.png

用例


     // 省略import
     public class ThreadUtil
     {
         private static final int MIXED_MAX = 128;  //最大线程数
         private static final String MIXED_THREAD_AMOUNT = "mixed.thread.amount";
     
         //懒汉式单例创建线程池:用于混合型任务
         private static class MixedTargetThreadPoolLazyHolder
         {
             //首先从环境变量 mixed.thread.amount 中获取预先配置的线程数
             //如果没有对 mixed.thread.amount进行配置,就使用常量 MIXED_MAX作为线程数
             private static final int max = 
                               (null != System.getProperty(MIXED_THREAD_AMOUNT)) ?
                     Integer.parseInt(System.getProperty(MIXED_THREAD_AMOUNT))
                                                                           : MIXED_MAX;
             //线程池:用于混合型任务
             private static final ThreadPoolExecutor EXECUTOR = 
                                                               new ThreadPoolExecutor(
                     max,
                     max,
                     KEEP_ALIVE_SECONDS,
                     TimeUnit.SECONDS,
                     new LinkedBlockingQueue(QUEUE_SIZE),
                     new CustomThreadFactory("mixed"));
     
             static
             {
                 EXECUTOR.allowCoreThreadTimeOut(true);
                 //JVM关闭时的钩子函数
                 Runtime.getRuntime().addShutdownHook(
                     new ShutdownHookThread("混合型任务线程池", new Callable<Void>()
                 {
                     @Override
                     public Void call() throws Exception
                     {
                         //优雅地关闭线程池
                         shutdownThreadPoolGracefully(EXECUTOR);
                         return null;
                     }
                 }));
             }
         }
     }

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

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

相关文章

学习笔记-Windows 安全

Windows 安全 注 : 笔记中拓扑图 drawio 源文件在其图片目录下 免责声明 本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关. 大纲 漏洞利用 LOL RDP 命令行开启RDP多开连接记录凭据窃取绕过组策略限制绕过本地安全策略限制…

手机浏览器怎么下载视频,第三方手机浏览器下载视频的方法

在我们的手机中&#xff0c;总少不了一款手机浏览器。很多人经常使用手机浏览器看视频&#xff0c;那么如何在网页中将喜欢的视频下载下载下来呢&#xff1f;下面给大家讲解UC浏览器、多御安全浏览器、QQ浏览器下载视频的方法&#xff0c;有需要的朋友可以继续往下看。 UC浏览器…

如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用

稀疏矩阵的概念 一个mn的矩阵是一个由m行n列元素排列成的矩形阵列。矩阵里的元素可以是数字、符号及其他的类型的元素。 一般来说&#xff0c;在矩阵中&#xff0c;若数值为0的元素数目远远多于非0元素的数目&#xff0c;并且非0元素分布没有规律时&#xff0c;则称该矩阵为稀…

【数据结构】详解顺序表(图解)

目录一、顺序表的概念1.1、静态顺序表1.2、动态顺序表二、接口实现2.1、开辟一个动态顺序表及初始化2.2、顺序表的增容2.3、顺序表的尾插及尾删2.4、顺序表的头插及头删2.5、顺序表在pos处插入及删除数据2.6、顺序表的销毁及打印2.7、顺序表的查找及修改一、顺序表的概念 顺序表…

【linux/docker】解决ORA-28000: the account is locked

项目场景&#xff1a; oracle11g客户端连接失败 问题描述 java.sql.SQLException: ORA-28000: the account is locked 原因分析&#xff1a; 由于oracle 11g 在默认在default概要文件中设置了密码最大错误次数为10&#xff0c;“FAILED_LOGIN_ATTEMPTS10”&#xff0c;密码错误…

单商户商城系统功能拆解25—营销中心—优惠券

单商户商城系统&#xff0c;也称为B2C自营电商模式单店商城系统。可以快速帮助个人、机构和企业搭建自己的私域交易线上商城。 单商户商城系统完美契合私域流量变现闭环交易使用。通常拥有丰富的营销玩法&#xff0c;例如拼团&#xff0c;秒杀&#xff0c;砍价&#xff0c;包邮…

NumPy数组基础

一、NumPy数组属性 首先我们先了解一下NumPy 数组属性。NumPy 的数组中比较重要 ndarray 对象属性有&#xff1a; 属性说明ndarray.ndim秩&#xff0c;即轴的数量或维度的数量ndarray.shape数组的维度&#xff0c;对于矩阵&#xff0c;n 行 m 列ndarray.size数组元素的总个数…

Python应用开发——串口通信

Python应用开发——串口通信 目录Python应用开发——串口通信前言1 环境搭建2 硬件准备3 代码编写与测试3.1 简单测一下串口收发3.2 补充细节3.3 完善整个收发流程结束语前言 在嵌入式开发中我们经常会用到串口&#xff0c;串口通信简单&#xff0c;使用起来方便&#xff0c;且…

20:访问者模式

1&#xff1a;定义 封装一些作用于某种数据结构中的各元素的操作&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。 2&#xff1a;结构 访问者模式包含以下主要角色: 抽象访问者&#xff08;Visitor&#xff09;角色&#xff1a;定义了对每一个元…

Matlab 高光谱遥感数据处理与混合像元分解

教程从基础、方法、实践三方面对高光谱遥感进行讲解。基础篇&#xff0c;站在学员的角度去理解“高光谱”&#xff0c;用大家能听的懂的语言去讲述高光谱的基本概念和理论&#xff0c;帮助学员深入理解这项技术的底层科学机理。方法篇&#xff0c;将高光谱技术与MATLAB工具结合…

Yolov5:强大到你难以想象──新冠疫情下的口罩检测

初识Yolov5是看到一个视频可以检测街道上所有的行人&#xff0c;并实时框选出来。之后学习了CNN卷积神经网络&#xff0c;在完成一个项目需求时&#xff0c;发现卷积神经网络在切割图像方面仍然不太好用。于是我想到了之前看到的Yolov5&#xff0c;实战后不禁感慨一句&#xff…

50天50个前端小项目(纯html+css+js)第十八天(背景轮播图)

今天要做的是一个轮播图&#xff0c;不过是属于全屏类型的轮播图&#xff0c;先来看看效果&#xff1a; 点击左右按钮能切换背景&#xff0c;达到轮播图效果 来看代码实现部分&#xff0c;首先是html: <!DOCTYPE html> <html lang"en"><head>&…

四大含金量高的算法证书考试

证书考试推荐一、PAT 计算机程序设计能力测试二、CCF CSP认证三、团体程序设计天梯赛四、蓝桥杯大赛一、PAT 计算机程序设计能力测试 官网&#xff1a;PAT 计算机程序设计能力测试 PAT为浙江大学出的一款程序设计的测试网站&#xff0c;分为乙级、甲级、顶级三种&#xff0c;…

【MySQL 第十二天 事务的介绍|InnoDB使用事务】

【MySQL 第十二天 事务的介绍|InnoDB使用事务】【1】mysql事物的介绍【2】mysql事务处理的方法【3】mysql是u用InnoDB使用事务生命不息&#xff0c;学习不止 【1】mysql事物的介绍 atomicity 原子性&#xff1a;所有事情是统一的整体&#xff0c;必须一起执行&#xff0c;或者都…

2022 需求工程综合论述题【太原理工大学】

需求工程考题的最后一个模块 —— 综合论述题&#xff0c;只出一道题&#xff0c;30分&#xff0c;马上要考试了&#xff0c;临时抱佛脚其实还是非常管用的 hhh&#xff0c;简答、选择、填空及材料分析题前面博客已更&#xff0c;重点把下面这两个题看明白&#xff0c;仅供参考…

Real-Time Rendering——18.4 Optimization优化

Once a bottleneck has been located, we want to optimize that stage to boost the performance. In this section we present optimization techniques for the application,geometry, rasterization, and pixel processing stages. 一旦找到瓶颈&#xff0c;我们希望优化该…

Nginx 安全漏洞【CVE-2018-16843、CVE-2018-16844】解决办法

CVE-2018-16843和CVE-2018-16844漏洞影响 1.9.5 和 1.15.5 之间的所有 nginx 版本 解决办法&#xff1a;关闭http/2请求处理和MP4流媒体支持&#xff0c;将Nginx 升级至1.22.1 stable 最新版本。 操作步骤&#xff1a; 1、查看当前版本信息及配置参数&#xff1a; sudo /us…

深度学习入门(十三)前向传播、反向传播和计算图

深度学习入门&#xff08;十三&#xff09;前向传播、反向传播和计算图前言前向传播、反向传播和计算图教材前向传播前向传播计算图反向传播训练神经网络小结前言 核心内容来自博客链接1博客连接2希望大家多多支持作者 本文记录用&#xff0c;防止遗忘 前向传播、反向传播和计…

Android akptool 安装 mac 电脑

在之前&#xff0c;apktool工具包都是一个压缩包&#xff0c;下载后无需安装即可使用。下面我们看一下如何在Mac OS系统下如何安装 apktool工具包。 首先&#xff0c;需要下载下面几个软件或工具&#xff1a; Apktool&#xff1a;http://ibotpeaches.github.io/Apktool/instal…

【Spark NLP】第 18 章:人类标签

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…