Java提供的几个线程池,最终都是使用 ThreadPoolExecutor 这个类来实现的。
先看点基础的。
暂时不一上来就看怎么创建线程池,以及各个参数的作用等,先基本的走起。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
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; }
/*
* Bit field accessors that don't require unpacking ctl.
* These depend on the bit layout and on workerCount being never negative.
*/
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
源码里面有这么点属性和简单方法,都是最基本的,绕不开的东西。了解一下。
1,首先是一个原子类 AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
这个是在多线程操作的时候,记录线程池的一些状态和池里面线程的数量的载体。使用原子类,是为了线程安全。
源码中说,现阶段,暂时使用一个int类型的数字来表示信息,基本差不多够用了,里面可以包含2的29次方-1的线程数,差不多500million(百万),源码注释这么写的。要是后期不够用了,还可以扩展为long类型
2,int 类型的 COUNT_BITS = Integer.SIZE - 3;
/**
* COUNT_BITS 详解
*/
@Test
public void showCountBits() {
// 29 Integer.SIZE=32 意思就是integer使用了多少位来表达一个int数字。
System.out.println(Integer.SIZE);
// 4个字节,一个字节(byte)8位(bit)
System.out.println(Integer.BYTES);
System.out.println(COUNT_BITS);
System.out.println();
}
运行结果:
这个就解释了,这个数字 29哪里来的。
这个属性,就是说 int 类型 的 属性 ctl 的(二进制)29个二进制位来表示 work counter ,暂时没说是哪29个二进制位。
3,int 类型的 CAPACITY = (1 << COUNT_BITS) - 1;
@Test
public void showCapacity() {
// 二进制:000 + 29个1,的int值。
showOne("CAPACITY", CAPACITY);
// 二进制:111 + 29个0,的int值
showOne("~CAPACITY", ~CAPACITY);
int i = 7 & CAPACITY;
System.out.println("111 & CAPACITY: " + (Integer.toBinaryString(i)));
System.out.println();
// 32位中,第一位是0,其它的都是1,即 Integer.MAX_VALUE = 0 + 31 个1
System.out.println("Integer.MAX_VALUE 二进制:" + Integer.toBinaryString(Integer.MAX_VALUE));
System.out.println("Integer.MAX_VALUE 二进制的长度:" + Integer.toBinaryString(Integer.MAX_VALUE).length());
i = Integer.MAX_VALUE & ~CAPACITY;
System.out.println("Integer.MAX_VALUE & ~CAPACITY: " + (Integer.toBinaryString(i)));
System.out.println("Integer.MAX_VALUE & ~CAPACITY: " + (Integer.toBinaryString(i)).length());
}
运行结果:
容量:1左移29位 = 1后面29 个0,再减1 ,就等于29个1。就表示了容量,capacity单词也是这个意思。
取反之后,就是 111(3个1的二进制位)+29个0,然后 & 与运算,
runStateOf()方法是对 ~CAPACITY 与运算的,其实就是取int的前3位的值
workerCountOf()方法是对 CAPACITY 与运算的,其实就是取int的后29位的值
由此,int属性的32个二进制位都用来干吗的就分配完了。
4,线程池的几个状态
// runState is stored in the high-order bits
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;
/**
* 看看线程池的几个状态数字
* 这么看就明白了后面29个位,来控制线程的数量count,前面3位来表示线程池的状态,全1的即111表示running,
* 000-011是递增关系,同时也是线程池状态的衰败过程。
*/
@Test
public void showState() {
//111 - (29个0)
showOne("RUNNING", RUNNING);
//000 - (29个0)
showOne("SHUTDOWN", SHUTDOWN);
//001 - (29个0)
showOne("STOP", STOP);
//010 - (29个0)
showOne("TIDYING", TIDYING);
//011 - (29个0)
showOne("TERMINATED", TERMINATED);
}
运行结果:
这么看一下,线程池的几个状态,其实就是int的前3位来表示的;
全1的即111表示running,
(-1 << 29 :那就是32个1,左移29位,那就只剩下111 + 29个0啦,running的状态就是这么来的。)
000-011是递增关系,同时也是线程池状态的衰败过程。还预留了些位置,以备后用。
线程池几个状态之间的关系变化图
这个在源码的注释中也有写。
使用到的打印一个int数字的方法:
private void showOne(String name, int aInt) {
System.out.println(name + "的信息");
System.out.println("原始int值:" + aInt);
System.out.println("二进制的值:" + Integer.toBinaryString(aInt));
System.out.println("二进制的值的字符串的长度:" + Integer.toBinaryString(aInt).length());
System.out.println("--------------------------");
System.out.println();
}
5,线程池的2个关键数字
/**
* 线程池中的2个数字
* 1,线程池的状态
* 2,线程池中的线程数
*/
@Test
public void twoCountInPool() {
int c = ctl.get();
System.out.println("线程池的2个关键数字。。。");
poolState(c);
workerCount(c);
System.out.println();
}
/**
* 获取线程池的当前状态
*/
private void poolState(int c) {
System.out.println("线程池的状态。。。");
int i = runStateOf(c);
showOne("test state", i);
System.out.println();
}
/**
* 获取线程池中当前的线程数
*/
private void workerCount(int c) {
System.out.println("线程池的线程数。。。");
int i = workerCountOf(c);
System.out.println("worker count is " + i);
}
运行结果:
默认是running状态,0个worker。