一、开场白
Java是面向对象编程,万事万物皆对象,讲究池化技术,可以避免对象频繁的创建、销毁,浪费性能。线程池作为线程的复用利器,工作中都用过,可以说是非常非常重要。面试时很多面试官也会重点考察这块知识,用归用,但你是否真的了解线程池的内部原理?
二、7个核心参数
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
1、corePoolSize(核心线程数):
2、maximumPoolSize(最大线程数):
3、keepAliveTime(最大空闲时间):
4、unit(存活时间的单位):
5、workQueue(任务队列):
6、threadFactory(线程工厂):
7、handler(拒绝策略):
三、状态、计数字段
// 高3位用来表示线程池的状态,后面的29位则表示线程数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; // 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; //二进制表示,29个1
// 线程池当前状态
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;
ctl是线程池的核心状态控制字段,本身是一个AtomicInteger,用来保证对ctl的操作都是线程安全的。这里利用位运算巧妙地将一个int(一个int 4个字节 即32位)拆成了两部分,高3位用来表示线程的状态,剩下的29位则表示工作线程数。这里就可以得知工作线程的数量上限即CAPACITY,大约有5亿。
这五种状态转换成二进制后如下所示:
状态相关的方法:
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
long getTaskCount() // 已完成和未执行的任务总数;
long getCompletedTaskCount() // 已完成的任务数量,小于等于taskCount;
int getLargestPoolSize() //线程池曾经创建过的最大线程数量。通过这个数据可以知道线程池是否满过,是否达到过maximumPoolSize;
int getPoolSize() //线程池中的的线程数量
int getActiveCount() // 正在运行任务的线程数量
四、线程池提交任务
Future<Object> future = executor.submit(task);
未完待续: 史上最全ThreadPoolExecutor梳理(下篇)