线程池原来是个外包公司,打工人我悟了

我们在工作中经常用到线程池,线程池(Thread Pool)是一种基于池化思想管理线程的工具。

线程的作用是处理任务,而池则是帮助我们实现资源的重复利用和管理。线程池就是帮助我们异步处理任务的工具

很多时候技术设计思想往往可以从现实中找到映射的。
将线程池比作一个外包公司,那么提交给线程池的任务则可类比为给外包的需求,线程池中的线程则是外包公司内的打工人

带着这种类比思想,我们开始了解下线程池的原理。


1、线程池的创建

corePoolSize:核心线程数(默认核心线程数不销毁,但allowCoreThreadTimeOut参数为true时也是允许销毁的)
maximumPoolSize:线程池容许的最大线程池数
keepAliveTime和TimeUnit:线程空闲的最长时间
BlockingQueue<Runnable>:存储多余任务的有限阻塞队列
ThreadFactory:创建执行任务的线程的工厂
RejectedExecutionHandler:拒绝策略


2、外包公司的运行模式

通过threadPoolExecutor.execute(runnable);执行Runnable任务

image

外部将任务交付给线程池(甲方将需求交付给外包公司)

2.1、线程池内线程少于一定数量(corePoolSize),则创建线程来处理任务(每来一个任务,创建一个线程处理)

即:外包公司开始招人处理需求,人数达到一定数量后(公司认为一般情况下,这些人足以支持公司运营)

2.2、当线程总数达到指定数量(corePoolSize)后,仍有任务交付给线程池,此时线程池将任务暂存到队列(BlockingQueue<Runnable>,容量有限)中

即:甲方交付的需求过多时,外包公司则暂时将需求压下(压下的数量有限),等有人手空闲下来再处理。

2.3、队列装满之后,仍有多余任务,则类似第2步,为每个任务创建线程进行处理

即:当积压的需求超过公司承受能力时,公司开始又找人(直到到达公司人数上限)

2.4、当线程池总数量达到指定数量(maximumPoolSize)后,便不再创建。于是将多余任务进行特殊处理(拒绝策略)

即:需求再多时,外包公司已无力接手这些需求,于是拒绝这些任务(按某种方式处理这些需求,比如丢弃 或 让甲方自行处理)


3、打工人的艰辛

/**线程池内线程是以Worker的形式存在,因此总线程就是Worker集合*/
private final HashSet<Worker> workers = new HashSet<Worker>();

在上面的2.1和2.3中,每来一个任务,线程池创建一个线程处理

3.1、将首个要执行的任务(firstTask)和线程(thread)封装到worker对象(worker本身就是一个Runnable)中,并用thread执行worker任务。

Worker(Runnable firstTask) {
     setState(-1); // inhibit interrupts until runWorker
     this.firstTask = firstTask;
     this.thread = getThreadFactory().newThread(this);
  }
  
/** Delegates main run loop to outer runWorker  */
public void run() {
      runWorker(this);
}

3.2、worker的run方法只干一件事,就是while循环执行任务
(先处理firstTask,处理完后便从队列中获取任务)。


3.3、如果没有可执行的任务,worker也就结束了,自然thread也就可以销毁了

即:打工人进入公司,从此007不归路

要么在执行任务,要么在获取任务的路上。直到确定没有可处理的任务时就结束了(打工人打工魂)


4、打工人离职的方式

image

线程池的状态及变化过程:
RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED

4.1、线程池关闭时(状态变为SHUTDOWN且队列中没有了任务;或者 状态至少是STOP时),所有线程分别在完成正在执行的任务后,逐个销毁

即:公司倒闭了,所有员工完成手头任务后,纷纷离职

4.2、线程池线程总数超过maximumPoolSize后,多余的数量被所有线程CAS竞选,竞选到的则销毁

即:公司人数过多,需要优化部分名额。所有员工都可以竞选资格,竞选上的就离职了

4.3、当线程一段时间(keepAliveTime)内都没有获取到任务,且该线程可以被销毁(可以被销毁的判定条件:线程总数超过corePoolSize 或者 线程池中声明包括核心线程都可以被销毁),多余的数量被所有线程CAS竞选,竞选到的则销毁

即:公司人数超过人数下限(甚至公司声明没有人数下限)时,当有人一段时间内都没有处理业务时,此人就离职了

4.4、队列中只要仍有任务,就至少有一个线程存活;当队列没有任务时,可以容许所有线程都销毁

即:要任务时最少要留一人处理,没任务时是可以都离职的

总结

  • 任务加入到线程池后
    先尝试创建核心线程来处理;
    若达到核心线程数上限,则则加入队列;
    若队列已满,则尝试创建最大线程来处理;
    若达到最大线程数,则只能按照拒绝策略处理
  • 线程池中线程生命周期
    线程池伴随任务创建线程并复用线程,循环从队列中获取任务执行
    线程池销毁时机
    线程池销毁时所有线程都要销毁
    线程池中的线程数量超过上限(maximumPoolSize)时,多余销毁
    当线程空闲一段时间未处理任务,此线程要销毁(若允许销毁)
    当队列没有任务时,否则至少有一个线程存活,下限为0;

------The End------


如果这个办法对您有用,或者您希望持续关注,可以在wx公众号中搜索【码路无涯】,期待你的到来

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容