如何设置线程池参数?美团给出了一个让面试官虎躯一震的回答。(2)

简介: 如何设置线程池参数?美团给出了一个让面试官虎躯一震的回答。(2)

先劝退一波


为了不浪费你的时间,先检测一下你是否有阅读本文的基础知识储备:


首先,我们先自定义一个线程池:


拿着这个线程池,当这个线程池在正常工作的前提下,我先问你两个问题:


1.如果这个线程池接受到了 30 个比较耗时的任务,这个时候线程池的状态(或者说数据)是怎样的?


2.在前面 30 个比较耗时的任务还没执行完成的情况下,再来多少个任务会触发拒绝策略?


其实这就是在问你线程池的执行流程了,简单的说一下就是:


1.当接收到了 30 个比较耗时的任务时,10 个核心线程数都在工作,剩下的 20 个去队列里面排队。这个时候和最大线程数是没有关系的,所以和线程存活时间也就没有关系。


2.其实你知道这个线程池最多能接受多少任务,你就知道这个题的答案是什么了,上面的线程池中最多接受 1000(队列长度) + 30(最大线程数) = 1030 个任务。所以当已经接收了30个任务的情况下,如果再来 1000 个比较耗时的任务,这个时候队列也满了,最大线程数的线程也都在工作,这个时候线程池满载了。因此,在前面 30 个比较耗时的任务还没执行完成的情况下,再来 1001 个任务,第 1001 个任务就会触发线程池的拒绝策略了。


这两个问题你得会,如果答不上来你也别往下看了,大概率看的一脸懵逼。


我建议你先给本文点个赞,接着去网上搜一下线程池执行流程的文章(其实美团的那篇文章也写了执行流程),写个 Demo 跑一下,摸清楚了,再来看这篇文章。


巨人肩膀


对于线程池参数到底如何设置的问题美团的那篇文章提供了一个很好的思路和解决方案,展现的是一个大而全的东西。


但是,对于实施起来的细节就没有具体的展示了。


所以文本斗胆,站在巨人的肩膀上对细节处进行一些补充说明。



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


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


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


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


5.这个过程中涉及到的面试题有哪些?


下面从这五点进行展开说明。


现有的解决方案的痛点。


现在市面上大多数的答案都是先区分线程池中的任务是 IO 密集型还是 CPU 密集型。


如果是 CPU 密集型的,可以把核心线程数设置为核心数+1。

为什么要加一呢?


《Java并发编程实战》一书中给出的原因是:即使当计算(CPU)密集型的线程偶尔由于页缺失故障或者其他原因而暂停时,这个“额外”的线程也能确保 CPU 的时钟周期不会被浪费。


看不懂是不是?没关系我也看不懂。反正把它理解为一个备份的线程就行了。


这个地方还有个需要注意的小点就是,如果你的服务器上部署的不止一个应用,你就得考虑其他的应用的线程池配置情况。


经过精密的计算,你咔一下设置为核心数,结果项目部署上去了,发现还有其他的应用在和你抢 CPU,你想想难不难受。


如果是包含 IO 操作的任务呢?这个才是我们关心的东西。


《Java并发编程实战》一书中给出的计算方式是这样的:


理想很丰满,现实很骨感。


我之前有个系统就是按照这个公式算出来的参数去配置的。

结果效果并不好,甚至让下游系统直呼受不了。


这个东西怎么说呢,还是得记住,面试的时候有用。真实场景中只能得到一个参考值,基于这个参考值,再去进行调整。


我们再看一下美团的那篇文章调研的现有解决方案列表:


第一个就是我们上面说的,和实际业务场景有所偏离。


第二个设置为 2*CPU 核心数,有点像是把任务都当做 IO 密集型去处理了。而且一个项目里面一般来说不止一个自定义线程池吧?比如有专门处理数据上送的线程池,有专门处理查询请求的线程池,这样去做一个简单的线程隔离。但是如果都用这样的参数配置的话,显然是不合理的。


第三个不说了,理想状态。流量是不可能这么均衡的,就拿美团来说,下午3,4点的流量,能和 12 点左右午饭时的流量比吗?


基于上面的这些解决方案的痛点,美团给出了动态化配置的解决方案。


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


先来一个动态更新的代码示例:


上面的程序就是自定义了一个核心线程数为 2,最大线程数为 5,队列长度为 10 的线程池。


然后给它塞 15 个耗时 10 秒的任务,直接让它 5 个最大线程都在工作,队列长度 10 个都塞满。


当前的情况下,队列里面的 10 个,前 5 个在 10 秒后会被执行,后 5 个在 20 秒后会被执行。


再加上最大线程数正在执行的 5 个,15 个任务全部执行完全需要 3 个 10 秒即 30 秒的时间。


这个时候,如果我们把核心线程数和最大线程数都修改为 10。


那么 10 个任务会直接被 10 个最大线程数接管,10 秒就会被处理完成。


剩下的 5 个任务会在 10 秒后被执行完成。


所以,15 个任务执行完成需要 2 个 10 秒即 20 秒的时间处理完成了。


看一下上面程序的打印日志:


效果实现了,我先看一下原理是什么。


先看 setCorePoolSize 方法:



这个方法在美团的文章中也说明了:


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


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


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


看了美团的那篇文章后,我又去看了 Spring 的 ThreadPoolTaskExecutor类 (就是对JDK ThreadPoolExecutor 的一层包装,可以理解为装饰者模式)的 setCorePoolSize 方法: 注释上写的清清楚楚,可以在线程池运行时修改该参数。


而且,你再品一品 JDK 的源码,其实源码也体现出了有修改的含义的,两个值去做差值,只是第一次设置的时候原来的值为 0 而已。


哎,当时没有细细研究,恨自己看源码的时候不仔细。


接着看 setMaximumPoolSize 源码:


这个地方就很简单了,逻辑不太复杂。


1.首先是参数合法性校验。


2.然后用传递进来的值,覆盖原来的值。


3.判断工作线程是否是大于最大线程数,如果大于,则对空闲线程发起中断请求。


经过前面两个方法的分析,我们知道了最大线程数和核心线程数可以动态调整。

目录
相关文章
|
3月前
|
存储 安全 Java
每日大厂面试题大汇总 —— 今日的是“美团-后端开发-一面”
文章汇总了美团后端开发一面的面试题目,内容涉及哈希表、HashMap、二叉树遍历、数据库索引、死锁、事务隔离级别、Java对象相等性、多态、线程池拒绝策略、CAS、设计模式、Spring事务传播机制及RPC序列化工具等。
71 0
|
13天前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
13天前
|
Java 调度
|
2月前
|
监控 Java
线程池大小如何设置
在并发编程中,线程池是一个非常重要的组件,它不仅能够提高程序的响应速度,还能有效地利用系统资源。合理设置线程池的大小对于优化系统性能至关重要。本文将探讨如何根据应用场景和系统资源来设置线程池的大小。
|
2月前
|
SQL 缓存 关系型数据库
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴因未能系统梳理MySQL缓存机制而在美团面试中失利。为此,尼恩对MySQL的缓存机制进行了系统化梳理,包括一级缓存(InnoDB缓存)和二级缓存(查询缓存)。同时,他还将这些知识点整理进《尼恩Java面试宝典PDF》V175版本,帮助大家提升技术水平,顺利通过面试。更多技术资料请关注公号【技术自由圈】。
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
|
2月前
|
存储 安全 Java
美团面试:String 为什么 不可变 ?(90%答错了,尼恩来一个绝世答案)
45岁老架构师尼恩分享Java面试心得,涵盖String不可变性、字符串常量池、面试技巧等内容。尼恩强调,掌握深层技术原理,如String不可变性的真正原因,可在面试中脱颖而出,赢得高薪Offer。此外,尼恩还提供了大量技术资源和面试指导,帮助求职者提升技术水平,顺利通过大厂面试。
|
2月前
|
Java
线程池七大参数
核心线程数:线程池中的基本线程数量 最大线程数:当阻塞队列满了之后,逐一启动 最大线程的存活时间:当阻塞队列的任务执行完后,最大线长的回收时间 最大线程的存活时间单位 阻塞队列:当核心线程满后,后面来的任务都进入阻塞队列 线程工厂:用于生产线程
|
3月前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
3月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
3月前
|
SQL 存储 关系型数据库
美团面试:binlog、redo log、undo log的底层原理是什么?它们分别实现ACID的哪个特性?
老架构师尼恩在其读者交流群中分享了关于 MySQL 中 redo log、undo log 和 binlog 的面试题及其答案。这些问题涵盖了事务的 ACID 特性、日志的一致性问题、SQL 语句的执行流程等。尼恩详细解释了这些日志的作用、所在架构层级、日志形式、缓存机制以及写文件方式等内容。他还提供了多个面试题的详细解答,帮助读者系统化地掌握这些知识点,提升面试表现。此外,尼恩还推荐了《尼恩Java面试宝典PDF》和其他技术圣经系列PDF,帮助读者进一步巩固知识,实现“offer自由”。
美团面试:binlog、redo log、undo log的底层原理是什么?它们分别实现ACID的哪个特性?