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

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,                   // corePoolSize50,                   // maximumPoolSize60,                   // keepAliveTimeTimeUnit.SECONDS,     // keepAliveTime's unitnew LinkedBlockingQueue<>(100), // workQueueExecutors.defaultThreadFactory(), // threadFactorynew 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,                // corePoolSizenumCores * 2 + 1,            // maximumPoolSize60L,                         // keepAliveTimeTimeUnit.SECONDS,            // keepAliveTime's unitnew LinkedBlockingQueue<>(), // workQueueExecutors.defaultThreadFactory(), // threadFactorynew 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,                    // corePoolSizenumCores + 1,                // maximumPoolSize30L,                         // keepAliveTimeTimeUnit.SECONDS,            // keepAliveTime's unitnew SynchronousQueue<>(),    // workQueueExecutors.defaultThreadFactory(), // threadFactorynew 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,                // corePoolSizenThreads,                // maximumPoolSize60L,                     // keepAliveTimeTimeUnit.SECONDS,        // keepAliveTime's unitnew LinkedBlockingQueue<>(), // workQueueExecutors.defaultThreadFactory(), // threadFactorynew ThreadPoolExecutor.CallerRunsPolicy() // handler
);

6.总结

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

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

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

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

相关文章

springboot中,将某个函数的日志单独输出的方法

背景 项目中有个节点健康检查扫描功能&#xff0c;每10秒扫描一次节点。 如果节点挂掉&#xff0c;会输出健康检查失败的日志。 测试环境&#xff0c;虽然配置了多个节点&#xff0c;但并没有都启动&#xff0c;所以在扫描的时候&#xff0c;会不断的出现报错&#xff0c; 对于…

【low-ui-vue】实现原生可扩展动态表格组件

本文字数&#xff1a;3520字 预计阅读时间&#xff1a;20分钟 所谓动态列的表格&#xff0c;就是列数不固定。像广为使用的elementUI的table组件就是表头写死的&#xff0c;这种也叫列数固定的表格。 01 效果 当然&#xff0c;动态性增加了&#xff0c;当然要做出一定“牺牲”。…

【前端vue3】TypeScrip-Class类用法

类型声明 TypeScrip定义Class类 语法&#xff1a; // 定义一个名为 Person 的类 class Person {constructor () {// 构造函数&#xff1a;稍后定义}run () {// 方法&#xff1a;稍后定义} }在TypeScript是不允许直接在constructor 定义变量的 需要在constructor上面先声明 例…

csdn上传源码资源卖钱能买房买车吗?每天最高收入200-500?

csdn上传源码卖钱能买房买车吗,最高收入200-500&#xff1f; 作者收入日榜 不***孩 收益617.32元 程***妍 收益534.56元 s***n 收益323.71元 盈***客 收益315.05元 极***计 收益284.17元

2024-06-23 编译原理实验4——中间代码生成

文章目录 一、实验要求二、实验设计三、实验结果四、附完整代码 补录与分享本科实验&#xff0c;以示纪念。 一、实验要求 在词法分析、语法分析和语义分析程序的基础上&#xff0c;将C−−源代码翻译为中间代码。 要求将中间代码输出成线性结构&#xff08;三地址代码&#…

企业级Web项目中应该如何做单元测试、集成测试和功能测试?

先自我介绍下&#xff1a; 本人有过10年测试经验&#xff0c;也参与过公安部网络安全产品测试交付、华为4G 网络设备测试交付、腾讯QQ空间APP产品测试交付。 关于“企业级Web项目中应该如何做单元测试、集成测试和功能测试”这个问题&#xff0c;我想给大家唠唠&#xff0c;我…

38 - 换座位(高频 SQL 50 题基础版)

38 - 换座位 -- 方法一 select(casewhen id%21 and id(select max(id) from seat) then idwhen id%20 then id-1else id1end) as id, student fromseat order byid;-- 方法二selectif(id%20,id-1,if(id(select max(id) from Seat),id,id1)) as id,student fromSeat order by id…

陀螺仪LSM6DSV16X与AI集成(7)----FIFO数据读取与配置

陀螺仪LSM6DSV16X与AI集成.6--检测自由落体 概述视频教学样品申请源码下载主要内容生成STM32CUBEMX串口配置IIC配置CS和SA0设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置设置量程设置FIFO水印设置速率使用流模式设置FIFO时间戳批处理速率使能时间戳FIFO状态寄存器演示…

Django数据驾驶舱

Django数据驾驶舱 1.项目介绍2.项目结构3.库表结构3.1 appcsdn的models3.2 appssq的models3.3 appweather的models3.4 appweibo的models 4.功能展示5.解决问题5.1 路由配置5.2 后端数据与前端echarts展示5.3 长图表丝滑滚动条 6.遗留问题7.资源分享 1.项目介绍 这里介绍本人最…

阿里云发送验证码流程

目录 1. 阿里云短信服务简介 2. 阿里云验证码发送流程 2.1 申请阿里云短信服务 2.2 短信模板及阿里云秘钥 1.开发者可以在自己的应用程序中集成短信发送功能。绑定发起测试的手机号&#xff0c;需要绑定的手机号才能成功发送验证码&#xff0c;其他的用户手机号发送的验…

如何在 Ubuntu 12.04 VPS 上安装和配置基本的 LDAP 服务器

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 LDAP&#xff08;轻量级目录访问协议&#xff09;是一种通过文件和目录层次结构管理相关信息的协议&#xff0c;它可以从集中位置管…

【4003】基于springboot实现的线上阅读系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

ARM裸机:基础了解

ARM的几种版本号 ARM内核版本号 ARMv7 ARM SoC版本号 Cortex-A8 芯片型号 S5PV210 ARM型号的发展历程 m microcontroller微控制器 就是单片机 a application应用级处理器 就是手机、平板、电脑的CPU r realtime实时处理器 响应速度快,主要用在工业、航天等领域 soc 、cpu、…

ubutu 18.04源码编译安装freeswitch 1.10.7支持视频通话——筑梦之路

软件版本说明 ubuntu版本18.04&#xff1a;https://releases.ubuntu.com/18.04.6/ubuntu-18.04.6-live-server-amd64.iso freeswitch 版本1.10.7&#xff1a;https://files.freeswitch.org/freeswitch-releases/freeswitch-1.10.7.-release.tar.gz spandsp包&#xff1a;https:…

VB计算圆柱体积和表面积

已知圆半径和圆柱的高&#xff0c;计算圆柱体积和表面积。 Public Class Form1Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.ClickConst PI 3.14159Dim r As Integer, h As IntegerDim t As Single, s As Singler Val(TextBox1.Text)h V…

免杀笔记 ---> C语言

这次的更新可能有点慢&#xff0c;因为这段时间也比较忙&#xff0c;加上C语言还得和汇编结合&#xff0c;导致小编一个知识点总是得反复揣摩&#xff08;太菜了&#xff09;&#xff0c;所以免杀的更新篇幅长度可能会达到两个月和三个月&#xff0c;但是小编能保证&#xff0c…

动手学深度学习(Pytorch版)代码实践 -卷积神经网络-24深度卷积神经网络AlexNet

24深度卷积神经网络AlexNet import torch from torch import nn import liliPytorch as lp import liliPytorch as lp import matplotlib.pyplot as pltdropout1 0.5 #Alexnet架构 net nn.Sequential(nn.Conv2d(1, 96, kernel_size11, stride4, padding1),nn.ReLU(),nn.MaxPo…

智慧校园综合管理系统的优点有哪些

在当今这个信息化飞速发展的时代&#xff0c;智慧校园综合管理系统正逐步成为教育领域的一股革新力量&#xff0c;它悄然改变着我们对传统校园管理的认知。这套系统如同一个无形的桥梁&#xff0c;将先进的信息技术与学校的日常运作紧密相连&#xff0c;展现出多维度的优势。 …

训练营第四十五天 | 435. 无重叠区间763.划分字母区间56. 合并区间738.单调递增的数字968.监控二叉树

435. 无重叠区间 力扣题目链接(opens new window) 给定一个区间的集合&#xff0c;找到需要移除区间的最小数量&#xff0c;使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。 区间 [1,2] 和 [2,3] 的边界相互“接触”&#xff0c;但没有相互重叠。 示例 1…

6/22 第四周 python操作word

学习到了word有四个段落&#xff0c;都可以通过python来操作。 并且课程的体系&#xff0c;只是一个启蒙&#xff0c;需要在公司的项目中熟悉&#xff0c;从而具备专项测试的能力。 后续每天的学习笔记也需要侧重于理解的部分。