线程池源码剖析-execute方法
2021-02-10 19:00:22 3 举报
线程池源码剖析-execute方法
作者其他创作
大纲/内容
没有任务
加锁
//如果之前的线程已被销毁完,新建一个线程
for无限循环
异常
N
解锁
int c = ctl.get();int rs = runStateOf(c);获取线程池的状态
如果状态是running、shutdown,即前一步的 tryTerminate()没有成功终止线程池,尝试再添加一个worker
如果当前程状态和第一次for进来时的状态不一样,则说明线程池状态发生了改变,从外层开始循环
(wc > maximumPoolSize || (timed && timedOut))工作线程数 > 可扩展最大的核心线程数 或者 已经超时 或者 工作线程数>核心线程数timedOut : 非核心线程等待超时了&& (wc > 1 || workQueue.isEmpty())工作线程数 >1 或者 等待队列为空工作线程数 > 可扩展最大的核心线程数:可能是线程启动后来重置了maximumPoolSize的大小,这里的意思大概应该就是说:现在我已经等待超时了,而且你这时候队列也为空,还有核心线程,我自身就可以释放了
CAS成功
Worker.run()
重新获取int 32位
返回
!workerStarted线程任务启动是否成功
t.start()workerStarted = true
检查线程池状态是否正常
实际上就调用回去了,此时就添加一个空的任务线程Worker因为报错后前面workers.remove(w)
getTask()此方法我是觉得,第一从队列中取出task任务。第二主要是有一个timeout的判断,也就是如果此时worker数量超过了核心书,而且worker在很长时间都没获取到任务,然后poll也超时了,此时就返回了null,然后while循环退出,然后后面就直接 workers.remove(w) 移除了工作线程 ,所以核心线程和非核心线程,其实本质都是worker,移除的只是数量
是
如果min为0 && workQueue不为空说明至少需要保持一个线程
将worker加入Set集合 HashSet<Worker> workers
再次校验线程池,线程池不是RUNNING状态,并且remove(command)--workQueue.remove()成功,拒绝当前command其实是担心,放入队列之后,线程池此时状态被修改了,则当前任务就不能被添加队列了
workerAdded = trueworkerStarted = false
检查线程池状态
如果获取到r!=null
try 1
reject(command)拒绝该任务
否
return false
//1.当前池中线程比核心数少,新建一个线程执行任务
task = null;w.completedTasks++;这个应该只是每个线程的执行任务数w.unlock();
Y
execute
工作线程<corePoolSize
null
因为解锁是finally ,所以要先解锁
wc
timedOut = true
一样
tryTerminate()//尝试终止线程池
workerCountOf(c)工作线程
setState(-1);this.firstTask = firstTask;this.thread = getThreadFactory().newThread(this)ThreadFactory 创建线程
工作线程是否>最大核心线程
workers.remove(w)//把worker的完成任务数加到线程池的完成任务数//从HashSet<Worker>中移除
创建Worker
workerAdded = falseworkerStarted = false
不正常
失败
执行任务
如果之前创建的线程被销魂工作线程 == 0
false
min = 1 至少保持一个线程数
int c = ctl.get()//由它可以获取到当前有效的线程数和线程池的状态
allowCoreThreadTimeOut 默认是 false,也就是核心线程不允许进行超时;如果为false(默认),则即使处于空闲状态,核心线程也保持活动状态。 如果为true,则核心线程使用keepAliveTime来超时等待工作。
如果工作线程数>= min
task != null || (task = getTask()) != null任务不为空或者从任务队列中获取的任务不为空,则进入while循环
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;allowCoreThreadTimeOut 默认是 false,也就是核心线程不允许进行超时然后我们就是需要工作线程什么时候超过核心线程
线程池状态running&&加入队列成功
min == 0&& 队列不为空
说明还有工作线程
finally 2
启动失败
未超时
成功
这里:只有当run异常、或者非核心线程未取到数据超时时,走到这里删除worker
CAS -1 减少工作线程worker
//添加一个没有firstTask的worker//只要worker是completedAbruptly突然终止的,或者线程数量小于要维护的数量,就新添一个worker线程,即使是shutdown状态
正常run,其他情况都是false
这里应该是释放了非核心线程数的数量但是还要等到后面去 workers.remove(w)真正的移除
检查当前线程是否需要中断(暂时不看)
Worker重要
while无限循环
工作线程 < 核心线程数则直接创建线程
if (command == null) throw new NullPointerException();execute 里面的runnable为null,则报错
try 3
常用参数说明://ThreadPoolExecutorprivate static final int COUNT_BITS = Integer.SIZE – 3; //32-3=29,线程数量所占位数private static final int CAPACITY = (1 << COUNT_BITS) – 1; //低29位表示最大线程数,229-1//五种线程池状态private static final int RUNNING = -1 << COUNT_BITS; /int型变量高3位(含符号位)101表RUNINGprivate static final int SHUTDOWN = 0 << COUNT_BITS; //高3位000private static final int STOP = 1 << COUNT_BITS; //高3位001private static final int TIDYING = 2 << COUNT_BITS; //高3位010private static final int TERMINATED = 3 << COUNT_BITS; //高3位011
break retry;跳出第一个for循环
核心线程 >= 低29位最大线程|| 或者核心线程 >= corePoolSize 或者 最大核心数(core ? corePoolSize : maximumPoolSize))注意:第一次addWorker的时候,传入的true代码最后再传入的时候,是false,注意一下
线程池处于运行状态RUNNING或者 线程池关闭且任务线程为空
获取工作线程worker数量wc
return null
retry
重新去获取任务getTask())
workers.remove(w)从工作线程集合中移除该Worker
正在运行的线程数自增成功后则将线程封装成工作线程Worker
Worker任务消费
//2.核心池已满,但任务队列未满,添加到队列中
超时
try 2
return true
new Worker(firstTask)封装、并创建线程
正常
队列中的任务
task.run()这里的task就是Worker中的Runnable
//3.核心池已满,队列已满,试着创建一个新线程注意此处传入的false
判断线程状态和队列元素
addWorker
finally 3
SynchronousQueue
非核心线程超时的判断
获取 c (32位) 获取线程状态
队列状态不正常,直接返回false
runWorker(Worker w)
没有任务的时候,会阻塞,基本不会走后面,除非run报错或者线程被终止了、还有可能就是非核心线程等待超时
只有t.start()成功才返回true
ThreadPoolExecutor
workerAdded线程任务是否添加成功
如果是意外退出的话,那么就需要把WorkerCount--
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;allowCoreThreadTimeOut感觉会跟非核心线程数退出相关
tryTerminate()//尝试终止线程池这个要看一下
getTask()
不是突然完成的,即没有task任务可以获取而完成的,计算min,并根据当前worker数量判断是否需要addWorker()
这里的start,其实就是我们前面的 Worker
completedAbruptly = false表示正常执行完毕
如果线程池状态 >= SHUTDOWN -> (也就说明线程池是非正常running状态)&& !(线程状态==SHUTDOWN && command==null && 队列workQueue不为空)也就是线程状态正常,并且队列中存在等待线程任务
获取到任务
rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())表示线程池的状态是非运行状态 && 状态是停止或者队列为空
跳出循环后,继续执行
return
CAS工作线程+1
completedAbruptly = true后面有用,注意该值得变化
当上面while超时都没有获取到任务的话,此时的worker非核心线程就在此时被移除了
线程池是否终止失败
结束
判断是否可以创建线程Worker
不是
其实这个方法、总结下来就是,线程池是running正常状态,然后如果核心线程数还未占满,则CAS核心线程数+1 ,脱出循环
超过核心线程数
CAS减少Worker线程数
重算线程池状态!= 初始线程池状态
CAS 工作线程 - 1
线程池是否终止队列是否为空
在对线程池有负效益的操作时,都需要“尝试终止”线程池主要是判断线程池是否满足终止的状态如果状态满足,但还有线程池还有线程,尝试对其发出中断响应,使其能进入退出流程没有线程了,更新状态为tidying->terminated
如果线程任务是正常完成的
创建失败
如果run异常,此时就会执行完后面的几个 finally之后就会调用下面的方法,进行线程销毁,如果异常,此时 completedAbruptly == true
0 条评论
回复 删除
下一页