Java并发之线程池ThreadPoolExecutor源码分析学习 (3)

不接受新任务,但是处理已经在阻塞队列的任务
高3位全是0,就是SHUTDOWN状态

0 << COUNT_BITS ​ 0的表示 00000000 00000000 00000000 00000000 ​ 往左移29位 00000000 00000000 00000000 00000000

STOP

不接受新任务,也不处理阻塞队列里的任务,并且会中断正在处理的任务
所以高3位是001,就是STOP状态

1 << COUNT_BITS ​ 1的表示 00000000 00000000 00000000 00000001 ​ 往左移29位 00100000 00000000 00000000 00000000

TIDYING

所有任务都被中止,workerCount是0,线程状态转化为TIDYING并且调用terminated()钩子方法
所以高3位是010,就是TIDYING状态

2 << COUNT_BITS ​ 2的32位2进制 00000000 00000000 00000000 00000010 ​ 往左移29位 01000000 00000000 00000000 00000000

TERMINATED

terminated()钩子方法已经完成
所以高3位是110,就是TERMINATED状态

3 << COUNT_BITS ​ 3的32位2进制 00000000 00000000 00000000 00000011 ​ 往左移29位 11000000 00000000 00000000 00000000

3.部分方法介绍

runStateOf(int c)

实时获取runState的方法

private static int runStateOf(int c) { return c & ~CAPACITY; } ~CAPACITY ~是按位取反的意思 &是按位与的意思 ​ 而CAPACITY是,高位3个0,低29位都是1,所以是 000 11111 11111111 11111111 11111111 ​ 取反的话就是 111 00000 00000000 00000000 00000000 ​ 传进来的c参数与取反的CAPACITY进行按位与操作 1、低位29个0进行按位与,还是29个0 2、高位3个1,既保持c参数的高3位 既高位保持原样,低29位都是0,这也就获得了线程池的运行状态runState

workerCountOf(int c)

获取线程池的当前有效线程数目

private static int workerCountOf(int c) { return c & CAPACITY; } CAPACITY的32位2进制是 000 11111 11111111 11111111 11111111 ​ 用入参c跟CAPACITY进行按位与操作 1、低29位都是1,所以保留c的低29位,也就是有效线程数 2、高3位都是0,所以c的高3位也是0 ​ 这样获取出来的便是workerCount的值

ctlOf(int rs, int wc)

原子整型变量ctl的初始化方法

//结合这几句代码来看 private static final int RUNNING = -1 << COUNT_BITS; private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); ​ private static int ctlOf(int rs, int wc) { return rs | wc; } RUNNING是 111 00000 00000000 00000000 00000000 ​ ctlOf是将rs和wc进行按位或的操作 ​ 初始化的时候是将RUNNING和0进行按位或 0的32位2进制是 00000000 00000000 00000000 00000000 ​ 所以初始化的ctl是 111 00000 00000000 00000000 00000000 核心方法源码分析

execute(Runnable command)方法

public void execute(Runnable command) { //需要执行的任务command为空,抛出空指针异常 if (command == null) // 1 throw new NullPointerException(); /* *执行的流程实际上分为三步 *1、如果运行的线程小于corePoolSize,以用户给定的Runable对象新开一个线程去执行 * 并且执行addWorker方法会以原子性操作去检查runState和workerCount,以防止当返回false的 * 时候添加了不应该添加的线程 *2、 如果任务能够成功添加到队列当中,我们仍需要对添加的线程进行双重检查,有可能添加的线程在前 * 一次检查时已经死亡,又或者在进入该方法的时候线程池关闭了。所以我们需要复查状态,并有有必 * 要的话需要在停止时回滚入列操作,或者在没有线程的时候新开一个线程 *3、如果任务无法入列,那我们需要尝试新增一个线程,如果新建线程失败了,我们就知道线程可能关闭了 * 或者饱和了,就需要拒绝这个任务 * */ //获取线程池的控制状态 int c = ctl.get(); // 2 //通过workCountOf方法算workerCount值,小于corePoolSize if (workerCountOf(c) < corePoolSize) { //添加任务到worker集合当中 if (addWorker(command, true)) return; //成功返回 //失败的话再次获取线程池的控制状态 c = ctl.get(); } /* *判断线程池是否正处于RUNNING状态 *是的话添加Runnable对象到workQueue队列当中 */ if (isRunning(c) && workQueue.offer(command)) { // 3 //再次获取线程池的状态 int recheck = ctl.get(); //再次检查状态 //线程池不处于RUNNING状态,将任务从workQueue队列中移除 if (! isRunning(recheck) && remove(command)) //拒绝任务 reject(command); //workerCount等于0 else if (workerCountOf(recheck) == 0) // 4 //添加worker addWorker(null, false); } //加入阻塞队列失败,则尝试以线程池最大线程数新开线程去执行该任务 else if (!addWorker(command, false)) // 5 //执行失败则拒绝任务 reject(command); }

我们来说一下上面这个代码的流程:

1、首先判断任务是否为空,空则抛出空指针异常
2、不为空则获取线程池控制状态,判断小于corePoolSize,添加到worker集合当中执行,

如成功,则返回

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxgfx.html