文章目录

  • Pre
  • 使用场景
    • 场景1:响应速度优先
    • 场景2:吞吐量优先
  • 线程池设置不合理发生的那些故障
  • 线程池的参数如何评估和配置???
    • 不用线程池?
    • 万能公式?
    • 线程池参数动态化?
  • 线程池的监控


Pre

每日一博 - Review线程池


使用场景

为了最大程度利用CPU的多核性能,并行运算的能力是不可或缺的。通过线程池管理线程获取并发性是一个非常基础的操作,让我们来看两个典型的使用线程池获取并发性的场景。

场景1:响应速度优先

用户发起的实时请求,服务追求响应时间。

使用线程池也是有考量的,这种场景最重要的就是获取最大的响应速度去满足用户,所以应该不设置队列去缓冲并发任务调高corePoolSize和maxPoolSize去尽可能创造多的线程快速执行任务


场景2:吞吐量优先

和上一个响应速度优先的场景区别在于, 这类场景任务量巨大,并不需要瞬时的完成,而是关注如何使用有限的资源,尽可能在单位时间内处理更多的任务,也就是吞吐量优先的问题。


所以应该设置队列去缓冲并发任务,调整合适的corePoolSize去设置处理任务的线程数。在这里,设置的线程数过多可能还会引发线程上下文切换频繁的问题,也会降低处理任务的速度,降低吞吐量。


线程池设置不合理发生的那些故障

【CASE 1】: 接口大量调用降级 -----------> 使用线程池做并行计算,由于没有预估好调用的流量,导致最大核心数设置偏小,大量抛出RejectedExecutionException,触发接口降级条件


【CASE 2】: 服务执行时间过长,作为上游服务整体超时,大量下游服务调用失败 ------------> 内部逻辑使用线程池做资源隔离,由于队列设置过长,最大线程数设置失效,导致请求数量增加时,大量任务堆积在队列中,任务执行时间过长,最终导致下游服务的大量调用超时失败

总结下:

  • 核心线程过小,阻塞队列过小,最大线程过小,导致接口频繁抛出拒绝策略异常
  • 核心线程过小,阻塞队列过小,最大线程过大,导致线程调度开销增大,处理速度下降
  • 核心线程过小,阻塞队列过大,导致任务堆积,接口响应或者程序执行时间拉长
  • 核心线程过大,导致线程池内空闲线程过多,过多的占用系统资源,造成资源浪费

如果线程池的配置涉及到上述问题,那么就有可能需要修改代码,重启业务来解决;如果发布后参数仍不合理,继续…


线程池的参数如何评估和配置???

不用线程池?

业务使用线程池是为了获取并发性,对于获取并发性,是否可以有什么其他的方案呢替代


万能公式?

业界的一些线程池参数配置方案:

面试官:你是如何评估一个线程池需要设置多少个线程

设置多少个线程数量通常是根据应用的类型:IO密集型、CPU密集型。

  • IO密集型通常设置为2n+1,其中n为CPU核数
  • CPU密集型通常设置为 n+1。

实际情况往往复杂得多

其实对于IO密集型类型的应用,网上还有一个公式:线程数 = CPU核心数/(1-阻塞系数)

引入了阻塞系数的概念,一般为0.8~0.9之间

在我们的业务开发中,基本上都是IO密集型,因为往往都会去操作数据库,访问redis,es等存储型组件,都会涉及到磁盘IO,网络IO。

IO密集型,可以考虑多设置一些线程,主要目的是可以增加IO的并发度,CPU密集型不宜设置过多线程,因为是会造成线程切换,反而损耗性能。

并没有得出通用的线程池计算方式。并发任务的执行情况和任务类型相关,IO密集型和CPU密集型的任务运行起来的情况差异非常大,但这种占比是较难合理预估的,这导致很难有一个简单有效的通用公式能直接计算出结果。


线程池参数动态化?

bingo ,这是正确的方式

动态化线程池的核心设计包括以下三个方面:

  1. 简化线程池配置:线程池构造参数有8个,但是最核心的是3个:corePoolSize、maximumPoolSize,workQueue,它们最大程度地决定了线程池的任务分配和线程分配策略。

    考虑到在实际应用中获取并发性的场景主要是两种:
    (1)并行执行子任务,提高响应速度。这种情况下,应该使用同步队列,没有什么任务应该被缓存下来,而是应该立即执行。
    (2)并行执行大批次任务,提升吞吐量。这种情况下,应该使用有界队列,使用队列去缓冲大批量的任务,队列容量必须声明,防止任务无限制堆积。
    所以线程池只需要提供这三个关键参数的配置,并且提供两种队列的选择,就可以满足绝大多数的业务需求

  2. 参数可动态修改:为了解决参数不好配,修改参数成本高等问题。在Java线程池留有高扩展性的基础上,封装线程池,允许线程池监听同步外部的消息,根据消息进行修改配置。将线程池的配置放置在平台侧,允许查看、修改线程池配置。

  3. 增加线程池监控:对某事物缺乏状态的观测,就对其改进无从下手。在线程池执行任务的生命周期添加监控能力,帮助了解线程池状态。


1.现有的解决方案的痛点


2.动态更新的工作原理是什么

在运行期线程池使用方调用此方法设置corePoolSize之后,线程池会直接覆盖原来的corePoolSize值,并且基于当前值和原始值的比较结果采取不同的处理策略。

对于当前值小于当前工作线程数的情况,说明有多余的worker线程,此时会向当前idle的worker线程发起中断请求以实现回收,多余的worker在下次idel的时候也会被回收;

对于当前值大于原始值且当前队列中有待执行任务,则线程池会创建新的worker线程来执行队列任务,setCorePoolSize具体流程如下:


3.动态设置的注意点有哪些?

在设置核心线程的时候,同时设置最大线程数就可以。只要工作线程不大于最大线程数,那么动态设置就是有效的


4.如何动态指定队列长度

这一种方式简单粗暴,直接把 LinkedBlockingQueue 代码复制出来一份,改个新名字 ResizableCapacityLinkedBlockIngQueue,然后把 capacity 所修饰的 final 关键字去掉,再加上一个 #setCapacity 方法

https://www.cnblogs.com/thisiswhy/p/12690630.html

https://juejin.cn/post/6991634257147854856

https://github.com/longtai94/dynamic-threadpool


线程池的监控

如果可以知道一部分线程池运行时指标,可以极大程度上的预防部分故障

  • 监控业务线程池的 当前负载以及峰值负载
  • 监控线程池在不同时间段 核心线程、最大线程、活跃线程数量指标
  • 监控线程 池阻塞队列相关指标,判断是否有任务积压的风险
  • 监控线程任务在 运行时抛出的异常数量,诊断投递的任务是否“健康”
  • 监控线程池执行 拒绝策略执行的次数,确定线程池参数是否合理


我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=vqa9hqsir7q9

每日一博 - Review线程池_02相关推荐

  1. 每日一博 - Review线程池

    文章目录 Pre 核心设计与实现 运行机制 线程池的生命周期 ctl 解读 ctl的相关方法 线程池的状态 任务执行机制 任务调度 任务缓冲 任务申请 任务拒绝 Worker线程管理 Worker线程 ...

  2. Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例源码分析

    文章目录 概述 Why 内存泄露 ? 在线程池中使用ThreadLocal导致的内存泄漏 概述 ThreadLocal的基本使用我们就不赘述了,可以参考 每日一博 - ThreadLocal VS I ...

  3. Java Review - 线程池资源一直不被释放案例源码分析

    文章目录 概述 问题复现 源码分析 小结 概述 在日常开发中为了便于线程的有效复用,经常会用到线程池,然而使用完线程池后如果不调用shutdown关闭线程池,则会导致线程池资源一直不被释放. 下面通过 ...

  4. Java Review - 线程池使用FutureTask的小坑

    文章目录 概述 问题复现 源码分析 解决办法 小结 概述 先说结论 线程池使用FutureTask时如果把拒绝策略设置为 DiscardPolicy和 DiscardOldestPolicy,并且在被 ...

  5. ARTS-11(动态规划、线程池解析、Feign原生接口调用、好用工具推荐)

    Algorithm 动态规划思路及解题 Review 线程池的使用 1).多线程的好处 提升资源利用率 提高程序处理效率:例如对执行顺序不敏感的任务,可以交由多个线程进行并行处理 减少了创建和销毁线程 ...

  6. 原理底层计划--线程池原理和常见的问题

    为什么要用线程池? 池化技术相比大家已经屡见不鲜了,线程池.数据库连接池.Http 连接池等等都是对这个思想的应用.池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率. 线程池提供了一 ...

  7. 【每日爬虫】:利用线程池爬取2万张装修效果图

    文章目录 一.前言 二.需求 三.技术路线 四.线程池爬取2万张装修效果图 五.其他 一.前言 2020-04-08日爬虫练习 每日一个爬虫小练习,学习爬虫的记得关注哦! 学习编程就像学习骑自行车一样 ...

  8. Java每日一讲线程池的总结

    Java每日一讲线程池的总结 目录

  9. Java Review - 创建线程和线程池时建议指定与业务相关的名称

    文章目录 概述 线程 不指定线程名称为何难定位问题 Thread默认的线程名称 指定线程名称 线程池 不指定线程池名称为何难定位问题 指定线程名称 自定义线程名称 小结 概述 在日常开发中,当在一个应 ...

最新文章

  1. 网易SRC指责白帽子私自披露已修复漏洞,强势表态违刑必究
  2. Block变量的的用法,使你的程序看起来清晰明了!
  3. [knownledge][latex] LaTex入门
  4. Eclipse中将java类打成jar包形式运行
  5. c语言mysql自动重连接_c++操作mysql数据库
  6. Oracle Segments可以跨多个data files吗?
  7. 移动Web开发基础概念
  8. matlab 30案例 目录,MATLAB-智能算法30个案例分析-终极版(带目录).doc
  9. asp.net中使用#include语法将文件添加到页面
  10. 轻松搞定对容器实例日志设置定期清理和回卷 1
  11. 触发器和存储过程的使用
  12. 官网下载STM32系列芯片的产品选型手册
  13. 优秀的求职者,是如何巧妙应对面试提问呢?
  14. 取消计算机触摸板,笔记本电脑触摸板,详细教您笔记本电脑触摸板怎么关闭
  15. 西北工业大学网络空间安全考研经验分享
  16. DirextX 11游戏开发(1)
  17. Python语法--Mooc七月
  18. 宽和窄俯卧撑哪个更难_窄距俯卧撑到底该多窄?
  19. 【html】svg标签
  20. 无能狂怒之我对配置类一无所知之自动填充和分页

热门文章

  1. ubuntu 安装 spconv
  2. 如何在DataFrame索引某一行
  3. 机器学习笔记:参数超参数
  4. torchvision 笔记:transforms.Normalize()
  5. 李宏毅线性代数笔记9:特征值与特征向量
  6. leetcode 目录
  7. 文巾解题 1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?
  8. 从C语言的角度重构数据结构系列(九)-数据结构哈希表分糖果
  9. 用Tableau画3D模型之四(放弃篇)
  10. 贝叶斯学习--极大后验假设学习