原创

线程池的工作原理


在实际开发工作中,如果并发的线程过多,并且每个线程执行一下就结束了,如此频繁的创建销毁线程,非常消耗时间并降低系统效率;因为引入线程池。

  • 什么是线程池?
  • 什么是核心线程?
  • 什么是阻塞队列?
  • 什么是非核心线程?
  • 什么是空闲存活时间?
  • 什么是饱和策略?
  • 任务拒绝策略
  • 常用线程池
  • 队列类型以及排队策略
  • 线程池工作原理流程图

什么是线程池?

在工作中,突然老板要求部门经理搞一个会员系统,两个月后完成,经理拍着胸口没问题。然后经理到开源众包服务提交系统需求,等待张三(线程A)接单,谈好合同,开始开发,项目交付,一个五脏俱全的会员系统终于完成了。老板很满意。

过了不久,老板再次发话:“公司业务发展壮大了,会员越来越多,迟到现象频频,再搞一个考勤系统吧”。经理又到开源众包服务提交系统需求,等待李四(线程B)接单。。。

逝者如斯,年底了,老板又提出开发一个文档管理中心,经理听了头疼不已,一天天的,重复到外部找人开发!

为了节省成本,招聘几个程序猿(线程A、B、C),成立IT技术部门(线程池)吧!” 老板听了,OK!!!


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


什么是核心线程?

线程池IT部门成立后,公司招聘了几个正式合同关系的程序猿a、b、c,经理管他们几个正式员工做核心线程。老板有需求任务过来,经理就把需求分配给手上没任务的线程处理。。。

什么是阻塞队列?

双国庆十一活动,老板到公司后,一口气提了5个需求,程序猿a、b、c按顺序领完任务后,发现还剩余2个需求任务。这个怎么安排呢?难道又要去开源众包服务找人吗?这不是搞笑嘛!!!

聪明的经理想到一个好办法,那就是可以搞一个需求池,把还没分配的需求,放进待完成的需求池里面,等待程序猿a、b、c谁完成任务,再把这个任务领走。这个需求池取名阻塞队列(WorkQueue)。

什么是非核心线程?

双11活动,双12活动快要来了,需求池(阻塞队列)已经堆积了几十个需求,排期都是满满的了。

经理跑到老板办公室,要求多招聘几个程序猿,老板说:“不行不行,财务开销有点大了!”

那就要求业务提少点需求任务?老板大了嗓门:“是不是傻,请求少点,不是自断财路嘛?”

“老板,我们可以去外包公司雇佣几个员工(d、e、f、g)一段时间,让他们来做需求池(阻塞队列)的任务。等完成需求,再派他们回去好了。” 老板一听,这个方案好呀。心里美滋滋:需求的活有人干了,公司财务又省钱,两全其美呀~

这几个派遣来的外包员工(d、e、f、g),我们就把它叫做非核心线程吧。

什么是空闲时间?

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

又有一天,到了18点所谓的下班时间,老板走出办公室,发现线程池IT部门的员工,都走得七七八八了。

心里一怒:“怎么一到下班时间就跑,工作这么不饱和了”。他随手点进需求池(阻塞队列),才发现,原来需求都被做完了。。。还有一堆外包员工(非核心线程)要发工资呢,这波亏大了~


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

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

什么是饱和策略?

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

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

这时候,需求还是做不完,怎么办呢?双11赶着上线呢?经理螺愁眉苦脸,潮起愁到潮落。。。

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

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


任务拒绝策略

当线程数达到maximunPoolSize,还有任务进来则执行拒绝策略。主要有四种类型

  • AbortPolicy(抛出一个异常,默认的)     丢弃任务抛出异常
  • DiscardPolicy(新提交的任务直接被抛弃)    丢失任务不抛异常
  • DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)    丢弃队列最前面(时间最久)的任务
  • CallerRunsPolicy(交给线程池调用所在的线程进行处理,即将某些任务回退到调用者)    由调度线程处理

常用线程池


  • newFixedThreadPool,corePoolSize与maximunPoolSize数量相等,使用LinkedBlockingQueue
  • newSingleThreadExecutor,corePoolSize与maximunPoolSize都为1,使用LinkedBlockingQueue
  • newCacheThreadPool,corePoolSize为0,maximunPoolSize为Integer.MAX_VALUE,使用SynchronuosQueue


队列类型以及排队策略

  1. ArrayBlockingQueue  先进先出,需要设置初始化的数组长度
  2. LinkedBlockingQueue 先进先出,默认长度为Integer.MAX_VALUE
  3. SynchronuosQueue  不保存任务,直接新建线程执行

线程池工作原理流程图


正文到此结束
该篇文章的评论功能已被站长关闭