tomcat优化面试题(线程池面试题核心参数拒绝策略)

tomcat优化面试题(线程池面试题核心参数拒绝策略)

adminqwq 2026-01-03 信息披露 13 次浏览 0个评论

线程池面试题:核心参数+拒绝策略,这么答才专业

在Java并发面试中,线程池绝对是“高频重难点”——从核心参数设置到拒绝策略选择,几乎每家公司(众安、猎上网、小硕科技、游族网络)都会追问。很多人要么记混“线程创建顺序”,要么核心线程数乱设,甚至不知道拒绝策略要分场景选。今天就拆解3道线程池高频题,帮你理清逻辑、避开坑,面试答得专业又透彻。

第一题:线程池有哪些核心参数?什么时候会创建新线程?(猎上网/众安必问)

这道题是“入门题”,但90%的人只会背参数名,说不出“核心线程满了之后,是先放队列还是先创临时线程”,更讲不清execute方法的底层逻辑。

先明确:ThreadPoolExecutor的6个核心参数(表格记,面试直接答)

核心参数

作用说明

关键细节(面试必提)

corePoolSize

核心线程数(常驻线程,空闲不销毁)

除非设allowCoreThreadTimeOut=true,否则核心线程不会超时销毁

maximumPoolSize

最大线程数(核心+临时线程总数)

临时线程数 = 最大线程数 - 核心线程数

keepAliveTime

临时线程空闲存活时间

超过这个时间,临时线程会被回收

workQueue

任务阻塞队列

核心线程满时,任务先放这里(如LinkedBlockingQueue)

threadFactory

线程创建工厂

自定义线程名(如“order-thread-1”),方便排查问题

handler

拒绝策略

队列满+线程数达最大时,触发的任务处理逻辑

关键补充:什么时候创建新线程?(execute方法逻辑)

线程池不是“有任务就创线程”,而是按固定顺序判断,记住4步:

判断核心线程是否满:若当前线程数 < corePoolSize,立即创建核心线程处理任务(哪怕有空闲核心线程,也会建新的,保证核心线程数满);判断队列是否满:若核心线程满了,把任务放入workQueue;判断最大线程是否满:若队列满了,且当前线程数 < maximumPoolSize,创建临时线程处理任务;触发拒绝策略:若队列满+线程数达最大,执行handler的拒绝逻辑。

举个例子:核心线程5,最大线程10,队列容量20。任务来了先创5个核心线程,再放20个任务到队列,队列满了再创5个临时线程,最后任务还多就拒绝。

踩坑点提醒(90%人会错)

❌ 错误逻辑:“核心线程满了就创临时线程”——跳过了“放队列”步骤!实际是先放队列,队列满了才创临时线程,这点和很多人的直觉相反;

❌ 忽略threadFactory:不自定义线程名,线上排查“线程泄露”时,看到“pool-1-thread-1”根本不知道是哪个业务的线程池;

❌ 误解allowCoreThreadTimeOut:以为核心线程永远不销毁,其实设为true后,核心线程也会超时回收(适合业务低谷时节省资源)。

第二题:核心线程数怎么设?CPU密集和IO密集场景有区别吗?(众安二面/小硕科技问过)

这道题考“工程落地能力”,很多人随便设个“10”“20”,却不知道要结合业务场景——“CPU密集设核数+1,IO密集看耗时比”,还有阿姆达尔定律(衡量并行优化效果)。

正确解答:分2种场景,用公式+例子算1. CPU密集型任务(如计算、排序)核心逻辑:线程数太多会导致“上下文切换”开销激增,反而变慢;计算公式:核心线程数 = CPU核数 + 1;例子:4核CPU→设5个核心线程。多1个线程是为了应对“偶尔的内存页失效、线程阻塞”,避免CPU空闲。2. IO密集型任务(如DB查询、网络请求)核心逻辑:线程大部分时间在等IO(如等DB返回、等接口响应),需要更多线程“占满CPU”;计算公式:核心线程数 = CPU核数 × [1 +(IO耗时 / CPU耗时)];例子:4核CPU,IO耗时100ms,CPU耗时10ms→4×(1+100/10)=44个核心线程。这样在100ms的IO等待期,CPU能处理44个线程的“CPU计算部分”。3. 兜底:用阿姆达尔定律验证

如果业务里“串行代码占比高”(比如必须单线程处理的逻辑),就算线程数再多,加速比也上不去。比如串行占比20%,就算线程数无限多,最大加速比也只有5倍(1/(0.2+0.8/∞)=5),这时不用设太多线程。

踩坑点提醒

❌ 不分场景乱设:IO密集任务设成“CPU核数”,导致线程不够用(比如4核设4个线程,IO等待时CPU空闲);

❌ 盲目加线程:以为线程越多越好,比如IO密集设100个线程,导致上下文切换频繁(每次切换耗时1-10μs,100个线程切换开销占CPU 20%以上);

❌ 忽略业务峰值:只按平时QPS设,比如平时100QPS设10个线程,峰值500QPS时任务堆积,要结合峰值预留1.5-2倍线程。

第三题:拒绝策略有哪几种?怎么选才合理?(猎上网/游族网络问过)

当队列满+线程数达最大时,拒绝策略决定“怎么处理多余任务”。有4种拒绝策略,但很多人只会说“AbortPolicy抛异常”,不知道要按业务重要性选。

先理清:4种拒绝策略对比(表格+适用场景)

拒绝策略

核心逻辑

适用场景

风险点

AbortPolicy

抛出RejectedExecutionException

核心业务(如支付、下单),需感知失败

没捕获异常会导致程序崩溃

DiscardPolicy

静默丢弃任务,不抛异常

非核心业务(如日志收集、统计)

任务丢了没监控,排查困难

DiscardOldestPolicy

丢弃队列最老的任务,加新任务

任务有“时效性”(如实时推荐)

可能丢重要老任务(如刚入队的订单)

CallerRunsPolicy

让“调用线程”(如main线程)自己执行任务

不想丢任务,且并发不高的场景

调用线程被阻塞,可能影响其他逻辑

关键补充:实际项目怎么选?核心业务(如订单创建):选AbortPolicy,但必须捕获异常,做重试(比如发MQ重试)或告警(钉钉/短信通知运维);非核心业务(如用户行为日志):选DiscardPolicy,但要加监控(比如用Prometheus统计丢弃数),避免丢太多没发现;实时性要求高的业务(如实时榜单):选DiscardOldestPolicy,但要确保“老任务不如新任务重要”(比如5分钟前的榜单数据可丢弃);低并发、不能丢任务的场景(如后台报表):选CallerRunsPolicy,哪怕调用线程阻塞,也比丢任务好。踩坑点提醒

❌ 核心业务用DiscardPolicy:比如支付任务被丢了,没监控根本不知道,线上出大事;

❌ 用CallerRunsPolicy不控制并发:高并发场景下,调用线程(如Tomcat线程)全被阻塞,导致整个服务无响应;

❌ 忽略拒绝策略的监控:不管选哪种策略,都要统计“拒绝次数”,不然任务丢了、异常了都没法排查。

互动话题

你项目里的线程池是怎么设参数的?有没有踩过“任务堆积”或“线程太多导致CPU飙升”的坑?评论区留个言,一起分析线程池配置是否合理~

#Java##线程##面试##CPU#

转载请注明来自海坡下载,本文标题:《tomcat优化面试题(线程池面试题核心参数拒绝策略)》

每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,13人围观)参与讨论

还没有评论,来说两句吧...