1. 概述
本文首先对Java线程池的整个工作流程做一个概述,之后再对其中一些值得思考的地方做一些源码解读
2. 工作模式
Java的线程池是一个worker thread
模式,这个模式非常简单,大概就是这么几点:
- 有一个任务队列
- 有一批工人
- 工人做完手头的工作后从任务队列里获取新的任务
- 人手不够的时候考虑增加新的工人
- 人手过多的时候,考虑辞退一部分工人~
这个过程差不多就对应着线程池的execute
方法,下面我们来看一下相关源码,相关内容已经写在了注释当中
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 工作线程小于核心线程数,相当于核心员工还没招够
// 此时要大规模招聘工人
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 工作线程数达到核心线程数,此时尝试将任务放入任务队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 如果任务队列已满,尝试增加新的工作线程,
// 如果增加新的工作线程失败(达到最大线程数),则根据拒绝策略处理
else if (!addWorker(command, false))
reject(command);
}
}
显然代码中除了我们之前提到的,还有一些别的东西,比如ctl是个什么东西,拒绝策略又是怎么操作的,接下来我们一步步来看这些问题
2. 线程池状态+工作线程数=ctl?
ctl是一个32位的AtomicInteger,其高三位用来表示线程池状态,低29位用来表示工作线程数
所以说,clt的值是可以根据工作线程数和线程池状态拼出来的,其初始化也是根据值拼出来的。为什么不初始化为0?因为虽然工作线程一开始是0,但是线程池状态不是0
ctlOf()
方法就是负责拼凑的,其内容也是很容易理解
private static int ctlOf(int rs, int wc) {
return rs | wc; }
ctl
的初始化
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
一些相关字段
// 这个是用来做位移的,在这里就是29
private static final int COUNT_BITS = Integer.SIZE -