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

news2024/11/17 3:27:09

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利用率等参数进行计算,并定期监控系统负载进行调整。

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

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

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

相关文章

科学技术创新杂志科学技术创新杂志社科学技术创新编辑部2024年第12期目录

科技创新 基于均质与细晶化的高性能限动芯棒生产工艺优化与实践 吕鹏昊;刘松; 1-4 大地电磁测深法在水文地质勘察中的应用研究 熊俊杰;毛卫东; 5-8 电石乙炔法制取聚氯乙烯生产工艺分析 龚志平; 9-12《科学技术创新》投稿&#xff1a;cnqikantg126.com 地面三维…

【LeetCode:394. 字符串解码 + 栈 | 递归】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

VUE3实现个人网站模板源码

文章目录 1.设计来源1.1 网站首页页面1.2 个人工具页面1.3 个人日志页面1.4 个人相册页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1…

头歌资源库(13)背包问题

一、 问题描述 二、算法思想 这是一个背包问题&#xff0c;可以使用动态规划算法来解决。具体思路如下&#xff1a; 定义一个二维数组dp&#xff0c;dp[i][j]表示前i个物品在背包容量为j时能获取的最大价值。初始化dp数组的第一行和第一列为0&#xff0c;表示当只有一个物品或…

西木科技Westwood-Robotics人型机器人Bruce配置和真机配置

西木科技Westwood-Robotics人型机器人Bruce配置和真机配置 本文内容机器人介绍Bruce机器人Gazebo中仿真代码部署Bruce真机代码部署 本文内容 人形机器人Brcue相关介绍docker中安装Gazebo并使用Bruce机器人控制器更换环境配置 机器人介绍 公司&#xff1a;西木科技Westwood-R…

Microsoft AI Day:支持开放合作,普及技术应用,推进行业企业智慧化创新

微软在北京举办以“共创AI创新&#xff0c;智启无限可能”为主题的Microsoft AI Day活动&#xff0c;集中展示了在生成式智能技术加速发展普及的过程中&#xff0c;微软取得的最新技术突破与进展&#xff0c;并同步更新了在Microsoft Build 2024全球开发者大会上发布的一系列Az…

【MATLAB源码-第227期】基于matlab的北方苍鹰优化算法(NGO)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 鼠群优化算法&#xff08;Rat Swarm Optimization, RSO&#xff09; 简介 鼠群优化算法&#xff08;Rat Swarm Optimization, RSO&#xff09;是一种模仿鼠类群体觅食行为的优化算法。该算法属于群体智能算法&#xff0c;通…

Mathtype7.6最新破解版下载,功能超乎你想象!

嘿&#xff0c;亲爱的小伙伴们&#xff01;今天我要分享一个让你的学术生涯或教育工作变得轻松无比的秘密工具 —— Mathtype7.6最新破解版下载。&#x1f389; MathType最新Win官方版本下载如下: https://wm.makeding.com/iclk/?zoneid34223 MathType最新Mac官方版本下载如…

macOS聚集搜索功能开启与关闭

按下command空格弹出 使用搜索 关闭搜索 sudo mdutil -a -i off 启用搜索 sudo mdutil -a -i on

跟张良均老师学大数据人工智能|企业项目试岗实训开营

我国高校毕业生数量连年快速增长&#xff0c;从2021年的909万人到2022年的1076万人&#xff0c;再到2023年的1158万人&#xff0c;预计到2024年将达到1187万人&#xff0c;2024年高校毕业生数量再创新高。 当年高校毕业生人数不等于进入劳动力市场的高校毕业生人数&#x…

ardupilot开发 --- RTSP视频流 篇

我年轻时很穷&#xff0c;努力了几年&#xff0c;终于不再年轻了 0. 一些概念参考文献 0. 一些概念 RTSP服务、RTSP推流、RTSP拉流&#xff0c;缺一不可&#xff0c;尤其是RTSP服务。RTSP服务器、RTSP客户端。推流和拉流都是由客户端发起&#xff0c;向服务器发起对应的请求。…

安享智慧理财金融测试项目

1. 项目介绍 安享智慧理财金融系统是基于 Java 语言开发&#xff0c;集 PC 端、APP 端、WAP 端为一体的 P2P&#xff08;个人对个人&#xff09;的借贷系统&#xff0c;提供了完整的借款和投资功能。 web用户端 说明&#xff1a;PC 网站&#xff0c;供借款人和投资人使用功能…

Java面试八股之myBatis如何将SQL结果封装成目标对象并返回

myBatis如何将SQL结果封装成目标对象并返回 ResultMap与自动映射&#xff1a; MyBatis主要通过ResultMap来描述如何将SQL查询结果映射到Java对象上。如果查询结果的列名与对象的属性名一致&#xff0c;MyBatis能够自动进行映射。但当列名与属性名不匹配时&#xff0c;就需要…

【mysql】排错和调优

通用的一些排错方法。 1、查看进程信息 mysql> show full processlist;mysql> show processlist; 2、information_schema information_schema这张数据表保存了MySQL服务器所有数据库的信息。如数据库名&#xff0c;数据库的表&#xff0c;表栏的数据类型与访问权限等。…

【CT】LeetCode手撕—141. 环形链表

目录 题目1- 思路2- 实现⭐141. 环形链表——题解思路 3- ACM实现 题目 原题连接&#xff1a;141. 环形链表 1- 思路 模式识别 模式1&#xff1a;判断链表的环 ——> 快慢指针 思路 快指针 ——> 走两步慢指针 ——> 走一步判断环&#xff1a;若快慢相遇则有环&a…

LUA移植到STM32F4,移植REPL,通过RTT Viewer交互

概述 站内移植LUA多数是使用C函数调用LUA&#xff0c;并没有移植REPL交互端口 本文将REPL也移植进去&#xff0c;做了简单的适配 LUA源码使用标准C库函数&#xff0c;如fgets&#xff0c;fwrite等&#xff0c;在嵌入式环境中要使用fgets&#xff0c;fwrite等C库函数&#xff…

发论文idea来了!强化学习+Transformer,29个创新点汇总

基于Transformer的强化学习&#xff08;TRL&#xff09;是一种利用Transformer模型架构来改进和增强强化学习算法性能的方法。 这种方法通过结合Transformer模型强大的表示能力和强化学习的决策优化框架&#xff0c;显著提升了智能体的学习能力和适应能力&#xff0c;为我们解…

逻辑蕴含、函数依赖集的闭包、Armstrong公理、属性集闭包

一、引言 Armstrong公理-从给定的函数依赖集得到关系模式的完整依赖集 二、逻辑蕴含 1、定义 设F是关系模式R上的函数依赖集&#xff0c;X、Y是R的属性子集&#xff0c;对于R的每个满足F的关系实例r&#xff0c;若函数 依赖都成立&#xff0c;则称F逻辑蕴含。 记为&#…

今日分享:能源行业数据大屏与界面设计~

能源行业数据大屏设计时要紧扣行业主题&#xff0c;关注视觉效果、实时数据与动态效果、数据可视化和图表、布局与字体、交互性、告警功能、故事叙述、易读性和可维护性等多个方面。大家设计时可以从这几个方面进行检查调整&#xff0c;这样就可以设计出既美观又实用的能源行业…