嗨环球好,我是小米ag百家乐直播,一个在Java圈里摸爬滚打了十来年的老措施员。
最近为了跳槽,刷了一波社招口试题,发现不少公司王人很心爱考多线程关系的内容。比如这说念看似浅薄,实则潜藏高明的题目:
「请你醒目说说 ScheduledThreadPoolExecutor 的旨趣和愚弄场景。」
看到这题,我不禁念念起了两年前在神情里踩过的一个坑。那时候,我们要作念一个定时任务系统,我信心满满地用 ScheduledThreadPoolExecutor 写了一套,恶果上线本日差点把工作器搞挂。今天我们就来围绕这说念口试题,聊聊我踩过的坑、回顾的教训,还有这个类背后的高明。
故事开场:那年我和定时任务打的交说念
事情要从我在上一家公司提及。那会儿我们有个需求,要定时去拉取供应商的库存数据,好像每隔 30 秒跑一次任务。
我那时写了个浅薄的代码:
部署上去,前两天一切平时,环球王人普天同庆。恶果上线第三天,工作器 CPU 顷刻间飙到了 90%,运维小哥径直冲到我工位前:“小米,快望望你的定时任务,是不是死轮回了?”
我一查日记,好家伙,尽然有个任务跑飞了。
什么是 ScheduledThreadPoolExecutor?
说到这,我们得先庄重先容一下这位“罪魁首恶”:
ScheduledThreadPoolExecutor 是 JDK 自带的一个定时任务线程池,接纳自 ThreadPoolExecutor,主要用来践诺定时任务,或者周期性叠加践诺的任务。
它是 ScheduledExecutorService 接口的一个具体罢了类,比起早期的 Timer,它愈加雄厚、生动、线程安全。常见的创建方法:
这里的 5 是线程池的中枢线程数目。
中枢方法
schedule(Runnable command, long delay, TimeUnit unit)延长一定时间践诺任务。
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)固定速度周期践诺,任务开动的时技能隔是固定的。
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)固定延长周期践诺,任务为止到下一个任务开动的时技能隔是固定的。
到底是那处出问题了?
那时我用的是 scheduleAtFixedRate,我们来望望它的践诺样式:
固定速度,假定第一个任务在 0 秒践诺,第二个任务应该在 30 秒时践诺。
如果前一个任务践诺逾越了 30 秒,后一个任务就会坐窝开动,甚而会并发践诺。
我查了日记,发现存一个供应商接口超时了,卡了 40 秒,恶果线程池没等它践诺完,下一个任务时间点到了,径直新开线程践诺,几个周期下来,ag百家乐贴吧线程就堆满了。
中枢线程池 5 个根蒂不够用,任务越堆越多,CPU 径直飙上天。
旨趣拆解:ScheduledThreadPoolExecutor 的里面结构
1、底层结构图
2、践诺历程
调用 schedule 方法时,会创建一个 ScheduledFutureTask 对象,封装任务和触发时间。
将 ScheduledFutureTask 放入一个 DelayQueue 中(这个部队是无界的,按践诺时间排序)。
使命线程接续从部队里取出到期的任务,放到线程池践诺。
3、DelayQueue 是什么?
DelayQueue 是一个带延长时间的部队,只须到期的任务才气被取出。它基于 PriorityQueue 罢了,队头持久是最早到期的任务。
scheduleAtFixedRate 和 scheduleWithFixedDelay 差异
口试考点:
1、如果一个定时任务践诺时间逾越了周期时间,scheduleAtFixedRate 会怎么办?
谜底:
它会尽量补上,可能导致任务并发践诺。
scheduleWithFixedDelay 则持久是串行践诺,前一个任务完成后才开动预计延长。
正确用法 + 实战教训
1、创建样式推选:
推选我方 new,别用 Executors.newScheduledThreadPool,因为它会把中枢线程数设死,容易堆积。
指定拒却计谋,阻扰线程过多。
2、相配处理
默许如果任务抛相配,线程会挂掉,导致线程池线程数减少,临了没东说念主可用。
惩办目的:
或者合股开辟 setRemoveOnCancelPolicy(true)。
3、颐养线程池参数
及时监控线程池状况,稳健增减中枢线程数,或者开辟最大线程数。
口试必问点
我回顾了以下几条,口试官最爱问:
1、ScheduledThreadPoolExecutor 和 Timer 差异?
Timer 单线程,任务相配会导致系数颐养罢手。
ScheduledThreadPoolExecutor 多线程,相配不影响其它任务。
2、scheduleAtFixedRate 和 scheduleWithFixedDelay 差异?
3、ScheduledThreadPoolExecutor 的底层结构?
4、DelayQueue 是怎么保证任务法例的?
5、如果线程池满了怎么办?
我的回顾
别看 ScheduledThreadPoolExecutor 小小一个类,细节一堆,坑也不少。
用得好,坐褥雄厚; 用不好,分分钟上热搜。
如果你要用它作念定时任务颐养,记着这 5 条:
尽量 new ScheduledThreadPoolExecutor,别用 Executors 工场方法。
用 scheduleWithFixedDelay 替代 scheduleAtFixedRate,阻扰任务堆积。
合股 try-catch,幸免相配导致线程挂掉。
竖立拒却计谋,阻扰 OOM。
及时监控线程池状况,生动颐养参数。
友情请示
说到底,口试问这个问题,教师的不是你会不会写定时任务,而是你:
是否领略多线程的本色
能弗成展望到实验运行时的问题
有莫得调优和容错的雄厚
这才是一个熟识 Java 措施员该有的形貌。
END
如果你心爱这么的口试故事+源码分解,铭记温雅小米!我们下次口试题陆续聊。
如若你也有相通的踩坑故事ag百家乐直播,批驳区走一个,我来帮你分析分析!