23

一文读懂线程池的工作原理(故事白话文)

 3 years ago
source link: http://developer.51cto.com/art/202010/629340.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

本文以程序员做需求的例子,比喻线程池的工作过程。以故事白话的方式展开,跟大家阐述线程池工作原理,以方便大家更好理解线程池,谢谢阅读哈~

什么是线程池?

什么是核心线程?

什么是阻塞队列?

什么是非核心线程?

什么是空闲存活时间?

什么是饱和策略?

线程池工作原理流程图&源码概览

github地址,感谢每一颗Star

?

https://github.com/whx123/JavaHome

?

公众号:「捡田螺的小男孩」

什么是线程池?

「小田螺」 勤勤恳恳,任劳任怨,夜以继日地工作着。终于有一天,他晋升为公司的主管,负责公司日常业务。

风轻云淡的一天,老板找到了小田螺,“我们公司员工越来越多了,我想搞个「员工管理系统」,你那边安排一下哈,要在一个月后完成。” 小田螺拍拍胸口,没问题!

因为当前公司还没有程序员,所以小田螺快马加鞭打开「猪八戒网」,提交员工管理系统需求,等待不久,「开发者(名字,线程A)」 接单,谈好合同,开始开发,系统交付...一系列流程下来,并且一个月过后,一个五脏俱全的员工管理系统终于完成了...老板对此大加赞赏~

过了不久,老板再次发话,“公司越来越多人迟到了,我们再搞个「考勤系统」吧!" 小田螺接到任务,马上又开始上猪八戒网,提需求找人开发,这次来了「线程B接单」......

逝者如斯,月底了,老板又提出开发个薪酬系统需求...小田螺听了头皮发麻,one day day的,重复去网上找人开发!“为了节省成本,不如我们雇佣几个程序员(线程a,b,c),成立自己的IT技术部门吧!我们就管IT部门叫「线程池」吧!”老板听了,一拍即合!!!

?

线程池就是管理线程的池子,当有任务要处理时,不用频繁创建新线程,而是从池子拿个线程出来处理。当任务执行完,线程并不会被销毁,而是在等待下一个任务。因此可以节省资源,提高响应速度。

?

什么是核心线程?

「线程池」IT部门成立后,雇佣了几个与公司有正式合同关系的员工a,b,c,「小田螺」管他们几个正式员工做「核心线程」。当老板提一个需求过来,小田螺就把需求分配给「手上没活干」的线程处理...

什么是阻塞队列?

一天早上,老板睡眼惺忪。来到公司后,一口气提了「四个需求」,a,b,c 按顺领完任务后,发现还剩余一个需求任务。这个怎么安排呢?难道又去「猪八戒兼职网」找人嘛?成立了「线程池IT部门」,还去找人(找线程干活),会被人笑落大牙的!

聪明的小田螺想到一个好办法,我们可以搞个DPMS需求池,把还没分配的需求,放进待完成的DPMS需求池里面吧,等到a,b,c谁先干完活,再把这个任务领走。这个DPMS需求池,我们给它取名「阻塞队列」,英文名叫「WorkQueue」吧!

什么是非核心线程?

又在一个晴空万里的午后,老板喝了一杯咖啡,闲来没事,就跑去「阻塞队列」(DPMS需求池)看看,一看就傻帽了!!需求池堆积了几十个需求,排期都是满满的了。老板马上叫「小田螺进来办公室」,以商量如何处理这些需求任务。

“要不,我们雇佣多几个员工(搞多几个「核心线程」)?” “不行不行,公司财务「开销」有点大!”

“要不然,我们要求业务提少点任务需求?(「请求少点」)” “你是不是傻,请求少点,不是自断财路嘛?你回家想想办法先吧!!”老板放大了他的嗓门~

小田螺回家闭目让神,每天早早就睡觉,两耳不闻窗外事...终于有一天,在一个梦香里,他想到了一个好办法。

“老板,我们可以去别的公司(「外包公司」)雇佣几个员工(假设名字为d,e,f,g)一段时间,让它们来做「DPMS需求池(阻塞队列)」 里面的需求。等到做完需求,再派他们回去就好啦。” 老板一听就乐了,这个方案好,心里美滋滋:「需求的活有人干了,公司财务又省钱,两全其美呀」~ 这几个派遣来的外包员工(d,e,f,g),我们就把它叫做「非核心线程」吧。

什么是空闲时间?

自从来了d,e,f,g外包员工(「非核心线程」),老板长舒一口气,这么多活,终于有人干了。

但是呢,又有一天,到了7点所谓的下班时间,老板走出办公室,发现「线程池」IT部门的员工,都走得七七八八了。心里一怒:「这帮粉肠,怎么一到下班时间就跑,工作这么不饱和了」?他随手点进DPMS需求池,才发现,原来需求都被做完了。。。还有一堆外包同事(非核心线程)要发工资呢,这波亏大了~

第二天,小田螺被「秘密」叫进了老板办公室,既然DPMS需求池都已经没需求了。我们准备派外包同事(非核心线程)回去吧?但是呢一般,需求一没有,就马上让他们回去(「线程回收」),如果需求一下子又来,就有点hold不住了...

“要不酱紫,我们等需求池空的时候,隔个15天还是10天,再让外包同事(「非核心线程」)回去吧?” 这个定义的15天或者10天,就是「线程空闲存活时间」啦

什么是饱和策略?

在临近双11的时候,不仅老板提了良多需求,新来的运营小姐姐们,也提了好多好多的需求。新需求如源头活水,滚滚的来~

首先呢,「线程池」IT部门a,b,c三个正式员工(核心线程)都忙于处理需求(「请求」),接着,DPMS需求池(「阻塞队列」)也被挤满了,最后呢,连d,e,f,g外包同事(「非核心线程」)也忙得不可开交。

这时候,需求还是做不完,怎么办呢?双11赶着上线呢?小田螺愁眉苦脸,从「潮起愁到潮落」...

没办法了,只能动用「饱和策略」啦。比如「丢弃需求任务」?「抛异常,告诉老板别加需求了」?「丢弃需求池最老的需求任务」?还是「交给提需求的人自己处理」?

最后老板决定,「拒绝再提新的需求」,于是「线程池」IT部门还是正常运行~

?

线城池的饱和策略事件,主要有四种类型

AbortPolicy(抛出一个异常,默认的)

DiscardPolicy(新提交的任务直接被抛弃)

DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)

CallerRunsPolicy(交给线程池调用所在的线程进行处理,即将某些任务回退到调用者)

?

线程池工作原理流程图 & 源码概览

故事讲完啦,再复习下线程池工作流程图吧~

有兴趣的朋友,源码也可以看下哈~

if (command == null)

throw new NullPointerException();

int c = ctl.get();

//判断当前活跃线程数是否小于corePoolSize

if (workerCountOf(c) < corePoolSize) {

//如果小于,则调用addWorker创建线程执行任务

if (addWorker(command, true))

return;

c = ctl.get();

}

//如果大于等于corePoolSize,则将任务添加到workQueue队列。

if (isRunning(c) && workQueue.offer(command)) {

int recheck = ctl.get();

if (! isRunning(recheck) && remove(command))

reject(command);

else if (workerCountOf(recheck) == 0)

addWorker(null, false);

}

//如果放入workQueue队列失败,则创建非核心线程执行任务

else if (!addWorker(command, false))

//(如果这时创建线程失败(当前线程数大于等于maximumPoolSize时))

调用reject拒绝接受任务

reject(command);


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK