工作中何如来合理分配核心线程数?
创始人
2024-04-02 18:38:28
0


文章目录

  • 一 回顾
    • 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 extendsMultithreadEventExecutorGroup 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核数的两倍

参考案例

// 省略importpublic 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核数*2IO_MAX,  //CPU核数*2KEEP_ALIVE_SECONDS,TimeUnit.SECONDS,new LinkedBlockingQueue(QUEUE_SIZE),new CustomThreadFactory("io"));static{EXECUTOR.allowCoreThreadTimeOut(true);//JVM关闭时的钩子函数Runtime.getRuntime().addShutdownHook(new ShutdownHookThread("IO密集型任务线程池",new Callable(){@Overridepublic Void call() throws Exception{//优雅地关闭线程池shutdownThreadPoolGracefully(EXECUTOR);return null;}}));}}}

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

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

案例

	// 省略importpublic 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(){@Overridepublic 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

用例

// 省略importpublic 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(){@Overridepublic Void call() throws Exception{//优雅地关闭线程池shutdownThreadPoolGracefully(EXECUTOR);return null;}}));}}}

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...