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

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

前言:曾经自诩对线程池了如指掌,不料看了美团的一篇技术文章后才知道原来线程池的参数还可以动态调节。


学艺不精,一边留下了没有技术的泪水,一边站在美团这个巨人的肩上写下此文,补充并记录了自己的一点看法。


分享给大家,希望能对你有所帮助。


荒腔走板


大家好,我是 why,一个四川好男人。


今天本来应该是武汉马拉松鸣枪起跑的日子,所以先荒腔走板说几句马拉松吧。


上面的图是我跑 2019 年成都马拉松的时候拍的,是一对双胞胎陪着 80 岁的父亲跑全程马拉松。


图片中的老人叫罗广德,在他 75 岁之前的人生和其他的老人并无不同。


但是经过他儿子的影响,在 75 岁的时候开始接触跑步的。一直就没有停下脚步,世界六大马拉松赛(纽约、伦敦、柏林、芝加哥、东京、波士顿)他已经完成了五个。


本来打算今年 4 月份站上波士顿马拉松的赛道上,完成最后的挑战。


完成之后,他就是世界华人这个年龄段里第一个完成世界六大马拉松赛的大满贯跑者。


但是由于疫情的原因,波士顿马拉松延期举行了。但是没有关系,我相信老爷子的执着,我也相信他会是第一人。


他说:“人生没有太晚的开始,关键是要行动起来。现在的年轻朋友很多都缺乏锻炼,作息时间不好,我希望年轻人都行动起来,我 80 岁都能跑步,难道你们不能跑吗?”


我之前说过,在赛道上你能看到很多有趣的、感动的画面。我喜欢跑马拉松,因为跑完之后总是能带给我爆棚的正能量。


人生需要一场马拉松,你可以迟到,但是你不能缺席。


好了,说回文章。


经典面试题


这次的文章还是绕回了我写的第三篇原创文章《有的线程它死了,于是它变成一道面试题》中留下的几个问题:


哎,兜兜转转,走走停停。天道好轮回,苍天饶过谁?


在这篇文章中我主要回答上面抛出的这个问题:你这几个参数的值怎么来的呀?

要回答这个问题,我们得先说说这几个参数是什么,请看截图:


其实,官方的注释写的都非常明白了。你看文章的时一定要结合英文,因为英文是 Doug Lea(作者)他自己写的,表达的是作者自己的准确的想法。

不要瞎猜好吗?



1.corePoolSize:the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set

(核心线程数大小:不管它们创建以后是不是空闲的。线程池需要保持 corePoolSize 数量的线程,除非设置了 allowCoreThreadTimeOut。)


2.maximumPoolSize:the maximum number of threads to allow in the pool。

(最大线程数:线程池中最多允许创建 maximumPoolSize 个线程。)


3.keepAliveTime:when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating。

(存活时间:如果经过 keepAliveTime 时间后,超过核心线程数的线程还没有接受到新的任务,那就回收。)


4.unit:the time unit for the {@code keepAliveTime} argument

(keepAliveTime 的时间单位。)


5.workQueue:the queue to use for holding tasks before they are executed. This queue will hold only the {@code Runnable} tasks submitted by the {@code execute} method。


(存放待执行任务的队列:当提交的任务数超过核心线程数大小后,再提交的任务就存放在这里。它仅仅用来存放被 execute 方法提交的 Runnable 任务。所以这里就不要翻译为工作队列了,好吗?不要自己给自己挖坑。)


6.threadFactory:the factory to use when the executor creates a new thread。


(线程工程:用来创建线程工厂。比如这里面可以自定义线程名称,当进行虚拟机栈分析时,看着名字就知道这个线程是哪里来的,不会懵逼。)


7.handler :the handler to use when execution is blocked because the thread bounds and queue capacities are reached。


(拒绝策略:当队列里面放满了任务、最大线程数的线程都在工作时,这时继续提交的任务线程池就处理不了,应该执行怎么样的拒绝策略。)


7 个参数介绍完了,我希望当面试官问你自定义线程池可以指定哪些参数的时候,你能回答的上来。


当然,不能死记硬背,这样回答起来磕磕绊绊的,像是在背书。也最好别给我回答什么:我给你举个例子吧,就是一开始有多少多少工人....


没必要,真的,直接回答每个参数的名称和含义就行了,牛逼的话你就给我说英文也行,我也能听懂。


这玩意大家都懂,又不抽象,你举那例子干啥?拖延时间吗?


面试要求的是尽量精简、准确的回答问题,不要让面试官去你冗长的回答中提炼关键字。

一是面试官面试体验不好。面试完了后,常常是面试者在强调自己的面试体验。朋友,你多虑了,你面试体验不好,回去一顿吐槽,叫你进入下一轮面试的时候,大部分人还不是腆着个脸就来了。面试官的体验不好,那你是真的没有下一轮了。


二是面试官面试都是有一定的时间限制的,有限的面试时间内,前面太啰嗦了,能问你的问题就少了。问的问题少了,面试官写评分表的时候一想,我靠,还有好多问题没问呢,也不知道这小子能不能回答上来,算了,就不进入下一轮了吧。


好了好了,一不下心又暴露了几个面试小技巧,扯远了,说回来。


上面的 7 个参数中,我们主要需要关心的参数是: corePoolSize、

maximumPoolSize、workQueue(队列长度)


所以,文本主要讨论这个问题:


当我们自定义线程池的时候 corePoolSize、maximumPoolSize、workQueue(队列长度)该如何设置?


你以为我要给你讲分 IO 密集型任务或者分 CPU 密集型任务?


不会的,说好的是让面试官眼前一亮、虎躯一震、直呼牛皮的答案。不骗你。


美团骚操作


怎么虎躯一震的呢?


因为我看到了美团技术团队发表的一篇文章:《Java线程池实现原理及其在美团业务中的实践》


第一次看到这篇文章的时候我真是眼前一亮,看到美团的这骚操作,我真是直呼牛皮。

(哎,还是自己见的太少了。)


这篇文章写的很好,很全面,比如我之前说的线程执行流程,它配了一张图,一图胜千言:



阻塞队列成员表,一览无余:


前面都是些基础知识,文中的后半部分才抛出了一个实际问题:


线程池使用面临的核心的问题在于:线程池的参数并不好配置。
一方面线程池的运行机制不是很好理解,配置合理需要强依赖开发人员的个人经验和知识;
另一方面,线程池执行的情况和任务类型相关性较大,IO密集型和CPU密集型的任务运行起来的情况差异非常大。
这导致业界并没有一些成熟的经验策略帮助开发人员参考。


美团给出的对应的解决方案是什么呢?


线程池参数动态化。


尽管经过谨慎的评估,仍然不能够保证一次计算出来合适的参数,那么我们是否可以将修改线程池参数的成本降下来,这样至少可以发生故障的时候可以快速调整从而缩短故障恢复的时间呢?
基于这个思考,我们是否可以将线程池的参数从代码中迁移到分布式配置中心上,实现线程池参数可动态配置和即时生效,线程池参数动态化前后的参数修改流程对比如下:


说实话看到这个图的时候我想起之前也有这样的想法的。


因为有一次我这边有个项目里面的定时任务用到了线程池,但是核心线程数和队列长度都设置的比较大,某一次任务触发后查出了大批数据,通过线程池提交任务,每个任务里面都会调用下游服务,导致下游服务长时间的压力过大,也没有做限流,所以影响了其对外提供的其他功能。


于是我叫运维帮我在 Apollo(配置中心)调小了核心线程数,并且重启了服务。


那一次我就在想,我们使用的是 Apollo 天然支持动态更新,那我能不能动态的修改线程池呢?


因为那个时候不知道一个构建好了的线程池,它的核心线程数和最大线程数是可以动态修改的。



所以最开始的想法是监听到参数变化后,直接弄一个新的线程池把原来的给替换掉。


但这样的问题是,偷天换日之后,原来的线程池里面的任务我怎么处理呢?


我不能等原来的线程池里面的任务执行完成后再换,因为这个时候任务一定是源源不断的过来的。


于是就卡在了这个地方。


说来惭愧,这块源码我看过几次,但还是差点火候,学艺不精,怨不得别人。

目录
相关文章
|
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的哪个特性?