Java-多线程并发之线程池

ThreadPoolExecutor:

ctl:Integer原子变量,高3位表示线程池的状态,其他的位数用来记录线程池线程个数。

线程池状态:
RUNNING:接受新任务并处理阻塞队列里的任务

SHUTDOWN:拒绝新任务并处理阻塞队列的任务

STOP:拒绝新任务并抛弃阻塞队列里的任务,同时会中断正在处理的任务

TIDYING:所有任务都执行完(包括阻塞队列)后当前线程池活动线程数位0,将要调用terminated方法。

TERMINATED:终止状态。terminated方法调用完成以后的状态。

 

RUNNING>>SHUTDOWN:显示或隐式(finalize)调用了shutdown方法。

RUNNING/SHUTDOWN>>>>STOP:显示调用了shutdownNow方法。

SHUTDOWN>>>>>TIDYING:当线程池和任务队列都空

STOP>>>TIDYING:线程池空的时候

TIDYING>>>>TERMINATED:当terminated()hook方法执行完成时。

 

线程池的启动: 

首先,构造线程池的时候,需要一些参数。一些重要的参数解释在 java内置的线程池笔记 文章中的结尾已经说明了一下重要参数的意义。

线程池构造完毕之后,如果用户调用了execute或者submit方法的时候,最后都会使用execute方法执行。

execute方法内部分3种情况处理任务:

  1. 如果当前正在执行的Worker数量比corePoolSize(基本大小)要小。直接创建一个新的Worker执行任务,会调用addWorker方法
  2. 如果当前正在执行的Worker数量大于等于corePoolSize(基本大小)。将任务放到阻塞队列里,如果阻塞队列没满并且状态是RUNNING的话,直接丢到阻塞队列,否则执行第3步
  3. 丢到阻塞失败的话,会调用addWorker方法尝试起一个新的Worker去阻塞队列拿任务并执行任务,如果这个新的Worker创建失败,调用reject方法

线程池中的这个基本大小指的是Worker的数量。一个Worker是一个Runnable的实现类,会被当做一个线程进行启动。Worker内部带有一个Runnable属性firstTask,这个firstTask可以为null,为null的话Worker会去阻塞队列拿任务执行,否则会先执行这个任务,执行完毕之后再去阻塞队列继续拿任务执行。

所以说如果Worker数量超过了基本大小,那么任务都会在阻塞队列里,当Worker执行完了它的第一个任务之后,就会去阻塞队列里拿其他任务继续执行。

Worker在执行的时候会根据一些参数进行调节,比如Worker数量超过了线程池基本大小或者超时时间到了等因素,这个时候Worker会被线程池回收,线程池会尽量保持内部的Worker数量不超过基本大小。

另外Worker执行任务的时候调用的是Runnable的run方法,而不是start方法,调用了start方法就相当于另外再起一个线程了。

Worker在回收的时候会尝试终止线程池。尝试关闭线程池的时候,会检查是否还有Worker在工作,检查线程池的状态,没问题的话会将状态过度到TIDYING状态,之后调用terminated方法,terminated方法调用完成之后将线程池状态更新到TERMINATED。

 

线程池的关闭:

shutdown:

shutdown方法,关闭线程池,关闭之后阻塞队列里的任务不受影响,会继续被Worker处理,但是新的任务不会被接受。回收闲置worker

shutdown方法中有一个interruptIdleWorkers()方法,用来中断闲置的worker,打断闲置Worker之后,getTask方法会返回null,然后Worker会被回收。 遍历worker,获取锁,获取到锁的很可能是闲置的worker,然后进行打断即可。

闲置Worker是这样解释的:Worker运行的时候会去阻塞队列拿数据(getTask方法),拿的时候如果没有设置超时时间,那么会一直阻塞等待阻塞队列进数据,这样的Worker就被称为闲置Worker。由于Worker也是一个AQS,在runWorker方法里会有一对lock和unlock操作,这对lock操作是为了确保Worker不是一个闲置Worker。

所以Worker被设计成一个AQS是为了根据Worker的锁来判断是否是闲置线程,是否可以被强制中断。

 

shutdownNow:

把状态设置成STOP。不会处理阻塞队列的任务。

打断用的是interruptWorkers。强行中断所有的worker执行,不管是不是闲置worker。回收所有的worker

 

 

关于TERMINATION:

 

 

Worker是通过继承AQS,使用AQS来实现独占锁这个功能。没有使用可重入锁ReentrantLock,而是使用AQS,为的就是实现不可重入的特性去反应线程现在的执行状态

 

参考文章:https://fangjian0423.github.io/2016/03/22/java-threadpool-analysis/

 

posted @ 2021-04-18 00:06  NobodyHero  阅读(115)  评论(0编辑  收藏  举报