【面试实战】# 并发编程之线程池配置实战

1.先了解线程池的几个参数含义

corePoolSize (核心线程池大小):

  • 作用: 指定了线程池维护的核心线程数量,即使这些线程处于空闲状态,它们也不会被回收。
  • 用途: 核心线程用于处理长期的任务,保持最低的线程数量,以减少线程的创建和销毁的开销。

maximumPoolSize (最大线程池大小):

  • 作用: 指定了线程池中允许的最大线程数。超过这个数量的线程将不会被创建。
  • 用途: 限制了线程池的大小,以防止资源耗尽。

keepAliveTime (线程空闲时间):

  • 作用: 当线程数超过 corePoolSize 时,多余的线程在空闲时间超过指定时间后将会被终止和回收。
  • 用途: 用于回收不再需要的线程,降低资源消耗。只对超过 corePoolSize 的线程起作用。

unit (时间单位):

  • 作用: 与 keepAliveTime 一起使用,指定线程空闲时间的时间单位(如秒、毫秒)。
  • 用途: 定义 keepAliveTime 的时间单位。

workQueue (任务队列):

  • 作用: 用于保存等待执行的任务的队列。

  • 用途

    : 管理任务的排队和处理方式,不同的队列类型可以影响线程池的行为。

    • 常见的队列类型有:
      • SynchronousQueue: 不存储任务,任务直接交给线程执行。如果没有空闲线程,则创建新线程。
      • LinkedBlockingQueue: 无界队列,可以存储任意多的任务。只有在任务队列为空时,才会创建新线程。
      • ArrayBlockingQueue: 有界队列,存储固定数量的任务,当队列满时,任务将被拒绝。

threadFactory (线程工厂):

  • 作用: 用于创建线程的工厂,可以定制线程的创建,比如设置线程名、优先级等。
  • 用途: 统一管理线程的创建细节,有助于调试和监控。

handler (饱和策略/拒绝策略):

  • 作用: 当任务无法提交给线程池(例如线程池已满且任务队列已满)时,如何处理新任务。

  • 用途

    : 定义任务无法被执行时的处理方式。

    • 常见策略有:
      • AbortPolicy: 抛出 RejectedExecutionException 异常。
      • CallerRunsPolicy: 由调用者线程执行该任务。
      • DiscardPolicy: 丢弃新提交的任务。
      • DiscardOldestPolicy: 丢弃队列中最旧的任务。

2.调整线程池配置应对高并发(常规操作)

为了应对高并发的需求,可以考虑以下调整:

  1. 增大 corePoolSizemaximumPoolSize:
    • 增加核心线程和最大线程数可以提高线程池的并发处理能力,减少任务的等待时间。
  2. 调整 keepAliveTimeunit:
    • 减少 keepAliveTime 可以更快地回收闲置线程,释放资源。相反,增加 keepAliveTime 适用于任务间隔较长的场景,以避免频繁创建和销毁线程。
  3. 选择合适的 workQueue:
    • 使用 SynchronousQueue 可以在任务很多但线程数不足时迅速增加线程数。
    • 使用 LinkedBlockingQueue 可以应对任务队列过长的问题,但可能导致线程数不会增加到最大。
    • 使用 ArrayBlockingQueue 适合在任务数有限的场景,防止资源耗尽。
  4. 合理配置 handler:
    • 根据系统需求选择适合的拒绝策略。比如,在希望任务尽量被处理时使用 CallerRunsPolicy,在任务不能丢失时选择 AbortPolicy
  5. 优化 threadFactory:
    • 使用自定义的线程工厂设置线程名、优先级、守护线程等,提高线程管理的清晰度和系统稳定性。
  6. 监控和调整:
    • 定期监控线程池的性能指标,如任务队列长度、线程使用率等,并根据实际情况动态调整参数配置。
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    10,                   // corePoolSize
    50,                   // maximumPoolSize
    60,                   // keepAliveTime
    TimeUnit.SECONDS,     // keepAliveTime's unit
    new LinkedBlockingQueue<>(100), // workQueue
    Executors.defaultThreadFactory(), // threadFactory
    new ThreadPoolExecutor.AbortPolicy() // handler
);

// 提交任务
executor.submit(() -> {
    // Task implementation
});

// 关闭线程池
executor.shutdown();

3.IO密集型、CPU密集型任务的合理配置(生产常用)

3.1 IO密集型任务

IO密集型任务:(例如网络操作、文件读写)通常不需要大量的CPU时间,但可能会等待IO操作的完成。为了有效利用系统资源,可以配置更多的线程来掩盖IO操作的等待时间。

配置建议:

  • corePoolSizemaximumPoolSize:
    • 建议的线程数通常远超过 CPU 核心数,因为线程在等待IO操作时不会占用CPU。可以使用 (CPU 核心数 * 2) 或更多,甚至是 (CPU 核心数 * 2) + 1 这种经验值。
    • 如果线程数太少,CPU资源可能未能充分利用。太多的线程可能会导致线程上下文切换的开销。
  • keepAliveTimeunit:
    • 适当地增加 keepAliveTime,让线程在空闲时保留一段时间,以便在短时间内有任务到达时无需重新创建线程。
  • workQueue:
    • LinkedBlockingQueue 是常见选择,因为它可以有效处理大量任务,而不需要频繁地创建和销毁线程。
    • SynchronousQueue 也可以用于高并发IO场景,确保任务直接交给线程执行,迅速响应。

示例:

int numCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor ioBoundExecutor = new ThreadPoolExecutor(
    numCores * 2,                // corePoolSize
    numCores * 2 + 1,            // maximumPoolSize
    60L,                         // keepAliveTime
    TimeUnit.SECONDS,            // keepAliveTime's unit
    new LinkedBlockingQueue<>(), // workQueue
    Executors.defaultThreadFactory(), // threadFactory
    new ThreadPoolExecutor.CallerRunsPolicy() // handler
);

3.2 CPU密集型任务

CPU密集型任务:(例如计算密集的操作、数据处理)主要消耗CPU 资源,因此线程数应该与 CPU 核心数相匹配,以避免过度的线程上下文切换和资源竞争。

配置建议:

  • corePoolSizemaximumPoolSize:
    • 通常设置为 CPU 核心数CPU 核心数 + 1
    • 过多的线程可能导致频繁的上下文切换,降低性能。
  • keepAliveTimeunit:
    • keepAliveTime 通常设置较短,适合及时回收空闲线程。
  • workQueue:
    • SynchronousQueueArrayBlockingQueue 是不错的选择,可以避免任务堆积,确保线程数控制在合理范围内。

示例:

int numCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor cpuBoundExecutor = new ThreadPoolExecutor(
    numCores,                    // corePoolSize
    numCores + 1,                // maximumPoolSize
    30L,                         // keepAliveTime
    TimeUnit.SECONDS,            // keepAliveTime's unit
    new SynchronousQueue<>(),    // workQueue
    Executors.defaultThreadFactory(), // threadFactory
    new ThreadPoolExecutor.AbortPolicy() // handler
);

3.3 关键考虑因素

  1. 系统资源和负载:
    • 监控系统的实际负载和资源使用情况,定期调整配置。
  2. 任务特性:
    • 根据任务的性质(长任务、短任务、IO 密集型、CPU 密集型)选择合适的线程池配置。
  3. 阻塞时间:
    • 对于 IO 密集型任务,理解和分析任务的阻塞时间,并根据其阻塞时间设置合适的线程池大小。
  4. 拒绝策略:
    • 合理选择拒绝策略(如 AbortPolicy, CallerRunsPolicy),确保系统在负载过高时能平稳处理任务。

4.专业级线程池配置(大厂规范)

4.1 线程池大小的计算公式

IO 密集型任务

对于IO密集型任务,可以使用以下公式计算适合的线程池大小:

file

  • N_threads: 推荐的线程池大小
  • N_cores: CPU核心数
  • W: 任务的等待时间(包括IO操作的等待时间)
  • C: 任务的计算时间
  • U: 期望的CPU使用率,通常设为0.8~0.9,避免CPU负载过高(0 < U < 1)

解释: 公式中的 W/C反映了IO操作占用的时间比,1 - U 是为了预留一定的CPU资源。

示例:

假设有一个任务,CPU核心数为8,IO等待时间为200ms,计算时间为100ms,期望的CPU使用率为80%,则推荐的线程池大小为:

file

这意味着你可能需要配置大约120个线程来处理IO密集型任务。

CPU 密集型任务

对于CPU密集型任务,线程池的大小通常可以通过以下公式估算:

file

在CPU密集型场景下,由于 W 很小或接近于零,因此公式通常简化为:

file

示例:

假设有一个任务,CPU核心数为8,计算时间大部分占用时间,等待时间可以忽略不计,则推荐的线程池大小为:

file

5.根据TPS和QPS进行线程池计算(生产常用)

其实和4的公式差不多

5.1 基础概念

  • TPS (Transactions Per Second): 每秒系统处理的事务数量。这通常用于描述系统处理更复杂的业务逻辑的能力。
  • QPS (Queries Per Second): 每秒系统处理的查询数量,通常用于衡量服务端API或数据库的查询处理能力。
  • 响应时间: 单个请求或事务的平均处理时间。

5.2 公式:

file

  • N_threads: 推荐的线程池大小
  • Q: 每秒的请求数(TPS 或 QPS)
  • R: 平均响应时间(秒)
  • U: 系统期望的CPU利用率(< 1, 通常为80%~90%)

解释: 公式描述了在满足特定吞吐量和响应时间的情况下,需要的线程数,预留了一部分CPU资源以防过载。

5.3 IO密集型、CPU密集型任务选择

这里我们主要举例说明IO密集型任务

因为:CPU密集型任务主要消耗CPU资源,线程数接近CPU核心数就足够,可以加一个额外的线程来处理。Nthreads=Ncores+1

IO密集型:

公式:

file

说明: 由于IO密集型任务在等待IO时不会占用CPU,因此线程数可以较高,适用于处理高并发的IO操作。

示例:

假设系统需要处理每秒500个请求(Q = 500),每个请求的平均响应时间为0.2秒,系统期望的CPU利用率为80%(U = 0.8):

file

这意味着你可能需要大约500个线程来处理这些IO密集型请求。

示例代码:

int qps = 500;
double responseTime = 0.2;
double targetUtilization = 0.8;

int nThreads = (int) (qps * responseTime / (1 - targetUtilization));

ThreadPoolExecutor ioBoundExecutor = new ThreadPoolExecutor(
    nThreads,                // corePoolSize
    nThreads,                // maximumPoolSize
    60L,                     // keepAliveTime
    TimeUnit.SECONDS,        // keepAliveTime's unit
    new LinkedBlockingQueue<>(), // workQueue
    Executors.defaultThreadFactory(), // threadFactory
    new ThreadPoolExecutor.CallerRunsPolicy() // handler
);

6.总结

  • IO密集型任务: 使用公式 file 计算线程池大小。
  • CPU密集型任务: 使用公式 file计算线程池大小。
  • 混合型任务: 综合IO和CPU的公式进行计算和调整。
  • file
    • W: 平均等待时间
    • C: 平均计算时间
  • 实际应用: 根据QPS或TPS、响应时间、期望的CPU利用率等参数进行计算,并定期监控系统负载进行调整。

合理的线程池配置可以显著提升系统的处理能力和资源利用率,因此根据具体需求和系统指标进行精细配置是至关重要的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【html】爱心跳动动画:CSS魔法背后的故事

效果展示&#xff1a; 代码介绍&#xff1a; 爱心跳动动画&#xff1a;CSS魔法背后的故事 在前端开发中&#xff0c;CSS不仅仅是一种用于控制网页样式的工具&#xff0c;它也是一种表达创意和想象力的艺术手段。今天&#xff0c;我要为大家介绍一段使用CSS实现的爱心跳动动画…

【计算方法】对分区间套解非线性方程

废话少说&#xff0c;直接上干货。 #include <stdio.h> #include <math.h>float f(float x) {// 函数return x*x*x - x - 1; }float root(float x1, float x2) {float mid, fmid;float e 1e-6;while ((x2 - x1) > e) {mid (x1 x2) / 2;fmid f(mid);// 判断中…

Android断点续传原理及实现

常见两种网络请求方式 一、 HttpURLConnection HttpURLConnection的setRequestProperty()方法&#xff0c;对我们要读取的字节部分进行控制&#xff0c;比如: 1.Range0-100代表只读取前100个字节。 2.Range100-500代表读取从第100个字节开始&#xff0c;读到第500个字节为止。…

从理论到实践掌握UML

统一建模语言&#xff08;UML&#xff09;是软件工程师用来设计软件系统的一种工具&#xff0c;就像是一套图形化的说明书。它让开发团队能够以图形化的方式来理解、设计和开发软件系统&#xff0c;比起用文字来描述&#xff0c;更加直观易懂。本文通过UML实例化的理论和实践相…

【漏洞复现】蓝凌EIS api.aspx 任意文件上传漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

指针的深入理解(3)(包括数组名的理解、一维数组传参的本质以及指针数组的相关知识及使用)

文章目录 1 数组名的理解2 使用指针访问数组3 一维数组传参的本质4 指针数组5 指针数组的使用 1 数组名的理解 当我们运行以下代码&#xff1a; #include <stdio.h> int main() {int arr[10] { 0 };printf("%p\n", &arr[0]);printf("%p\n", a…

矩阵中严格递增的单元格数

class Solution { public:int maxIncreasingCells(vector<vector<int>>& mat) {int m mat.size(), n mat[0].size();// 开辟用来记录每个值对应的位置&#xff08;i,j&#xff09;map<int, vector<pair<int, int>>> mp;vector<int> …

收银系统源码-千呼新零售2.0【线下促销】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货等连锁店使用。 详细介绍请查看下…

文件重命名 一键批量重命名10万+文件 简单效率高!

单个文件重命名大家应该都会操作&#xff0c;但是有一些人由于工作的场景等的情况&#xff0c;需要做大量的文件重命名&#xff0c;比如影楼、电商、仓库管理、图片处理等各种行业&#xff0c;都经常需要把一批文件&#xff0c;按一定的格式和规律给文件重命名。 一、批量文件重…

创建Docker容器与外部机通信(独立IP的方式)

需求&#xff1a;希望外部可以直接通过不同IP地址访问宿主机上的Docker容器&#xff0c;而不需要端口映射&#xff08;同一个IP不同的端口与外部通讯&#xff09;&#xff0c;这通常涉及到在宿主机的网络层面进行更高级的配置&#xff0c;比如使用IP伪装&#xff08;IP masquer…

HTML李峋同款跳动的爱心代码(双爱心版)

目录 写在前面 跳动的爱心 完整代码 代码分析 系列推荐 最后想说 写在前面 在浩瀚的网络世界中&#xff0c;总有一些小惊喜能触动我们的心弦。今天&#xff0c;就让我们用HTML语言&#xff0c;探索既神秘又浪漫的李峋同款跳动的爱心代码吧。 首先&#xff0c;让我们一起…

Linux系统编程——进程信号

目录 一&#xff0c;信号预备 1.1 生活中的信号 1.2 技术应用中的信号 1.3 signal函数捕捉信号 1.3 信号的发送与记录 1.4 信号的常见处理方式 二&#xff0c;信号的产生 2.1 核心转储 2.1.1 环境配置 2.1.2 利用core文件进行调试 2.1.3 core dump标志 2.2 通过系统…

【C语言】解决C语言报错:Null Pointer Dereference

文章目录 简介什么是Null Pointer DereferenceNull Pointer Dereference的常见原因如何检测和调试Null Pointer Dereference解决Null Pointer Dereference的最佳实践详细实例解析示例1&#xff1a;未初始化的指针示例2&#xff1a;释放内存后未将指针置为NULL示例3&#xff1a;…

STM32HAL库--NVIC和EXTI

1. 外部中断实验 1.1 NVIC和EXTI简介 1.1.1 NVIC简介 NVIC 即嵌套向量中断控制器&#xff0c;全称 Nested vectored interrupt controller。是ARM Cortex-M处理器中用于管理中断的重要组件。负责处理中断请求&#xff0c;分配优先级&#xff0c;并协调中断的触发和响应。 它是…

【会议征稿,IEEE出版】第四届电气工程与机电一体化技术国际学术会议(ICEEMT 2024,7月5-7)

第四届电气工程与机电一体化技术国际学术会议&#xff08;ICEEMT 2024&#xff09;定于2024年7月5-7日在浙江省杭州市隆重举行 。会议主要围绕“电气工程”、“机电一体化” 等研究领域展开讨论&#xff0c;旨在为电气工程、机电一体化等领域的专家学者、工程技术人员、技术研发…

STM32项目分享:智慧农业(机智云)系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…

如何灵活运用keil工具进行问题分析(2)— 定位FreeRTOS的栈溢出导致hardfault问题

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff08;2&#xff0…

【会议征稿,JPCS出版】第四届测量控制与仪器仪表国际学术会议(MCAI 2024,7月19-21)

随着各行各业向智能化、自动化、信息化方向发展&#xff0c;对于精密测量与控制的需求日益增加。同时该专业人才在科学研究、制造业、互联网等领域就业前景也非常广阔。测控技术与仪器是现代工程与科技的重要领域之一&#xff0c;为各行各业提供精准、可靠的测量、控制和检测手…

LuckySheet导入报错file.match is not a function解决方法

最近在研究有什么类Excel的表格库。目前看到的话就是luckysheet和univer。 univer是luckysheet的升级版&#xff0c;问题是开源版没有提供导入导出功能。 在尝试luckysheet的导入功能的时候&#xff0c;会发现官方demo是没有报错的。而在自己的项目里就会有报错 导入呢是官方提…

jsp运行提示_jsp.java某行存在错误问题的解决

jsp运行提示XXX_jsp.java某行存在错误问题的解决 在编译运行jsp文件时&#xff0c;出现类似如下提示&#xff1a; 49行发生错误&#xff0c;要注意&#xff1a; 这里所指的49行并非jsp文件的第49行&#xff0c;而是编译后的jsp.java文件的第49行。 因此&#xff1a;解决问题…