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

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

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

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

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

1、线程池的创建

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

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

2、外包公司的运行模式

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

线程池系列一:线程池原来是个外包公司,打工人我悟了
外部将任务交付给线程池(甲方将需求交付给外包公司)

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

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

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

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

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

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

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

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

3、打工人的艰辛

线程池系列一:线程池原来是个外包公司,打工人我悟了
/**线程池内线程是以Worker的形式存在,因此总线程就是Worker集合*/
private final HashSet workers = new HashSet();

在上面的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、打工人离职的方式

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

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

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

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

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

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

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

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

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

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

总结

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

Original: https://www.cnblogs.com/mlwy/p/15447139.html
Author: zy苦行僧
Title: 线程池系列一:线程池原来是个外包公司,打工人我悟了

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/576382/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球