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

线程池的执行流程就用参考资料里的图介绍一下了,具体我们还是通过代码去讲解。

在上面我们简单的讲解了一下Executors这个工厂类里的工厂方法,并且讲述了一下创建线程池的一些参数以及它们的作用,当然上面的讲解并不是很深入,因为想要弄懂的话是需要持续地花时间去看去理解的,而博主自己也还是没有完全弄懂,不过博主的学习方法是先学了个大概,再回头来看看之前的知识点,可能会更加好理解,所以我们接着往下面讲吧。

ThreadPoolExecutor源码分析

​ 在上面我们就发现了,Executors的工厂方法主要就返回了ThreadPoolExecutor对象,至于另一个在这里暂时不讲,也就是说,要学习线程池,其实关键的还是得学会分析ThreadPoolExecutor这个对象里面的源码,我们接下来就会对ThreadPoolExecutor里的关键代码进行分析。

AtomicInteger ctl

​ ctl是主要的控制状态,是一个复合类型的变量,其中包括了两个概念。

workerCount:表示有效的线程数目

runState:线程池里线程的运行状态

我们来分析一下跟ctl有关的一些源代码吧,直接上代码

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //用来表示线程池数量的位数,很明显是29,Integer.SIZE=32 private static final int COUNT_BITS = Integer.SIZE - 3; //线程池最大数量,2^29 - 1 private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits //我们可以看出有5种runState状态,证明至少需要3位来表示runState状态 //所以高三位就是表示runState了 private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; // Packing and unpacking ctl private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; } //用于存放线程任务的阻塞队列 private final BlockingQueue<Runnable> workQueue; //重入锁 private final ReentrantLock mainLock = new ReentrantLock(); //线程池当中的线程集合,只有当拥有mainLock锁的时候,才可以进行访问 private final HashSet<Worker> workers = new HashSet<Worker>(); //等待条件支持终止 private final Condition termination = mainLock.newCondition(); //创建新线程的线程工厂 private volatile ThreadFactory threadFactory; //饱和策略 private volatile RejectedExecutionHandler handler;

CAPACITY

在这里我们讲一下这个线程池最大数量的计算吧,因为这里涉及到源码以及位移之类的操作,我感觉大多数人都还是不太会这个,因为我一开始看的时候也是不太会的。

private static final int CAPACITY = (1 << COUNT_BITS) - 1;

从代码我们可以看出,是需要1往左移29位,然后再减去1,那个1往左移29位是怎么计算的呢?

1 << COUNT_BITS ​ 1的32位2进制是 00000000 00000000 00000000 00000001 ​ 左移29位的话就是 00100000 00000000 00000000 00000000 ​ 再进行减一的操作 000 11111 11111111 11111111 11111111 ​ 也就是说线程池最大数目就是 000 11111 11111111 11111111 11111111

2.runState

正数的原码、反码、补码都是一样的
在计算机底层,是用补码来表示的

private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;

RUNNING

可以接受新任务并且处理已经在阻塞队列的任务
高3位全部是1的话,就是RUNNING状态

-1 << COUNT_BITS 这里是-1往左移29位,稍微有点不一样,-1的话需要我们自己算出补码来 ​ -1的原码 10000000 00000000 00000000 00000001 ​ -1的反码,负数的反码是将原码除符号位以外全部取反 11111111 11111111 11111111 11111110 ​ -1的补码,负数的补码就是将反码+1 11111111 11111111 11111111 11111111 ​ 关键了,往左移29位,所以高3位全是1就是RUNNING状态 111 00000 00000000 00000000 00000000

SHUTDOWN

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

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