- 初始化
// 初始化线程池的状态和当前线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程池的状态和数量分别由一个32位的整形前3位和后29位表示
// 这个COUNT_BITS=29
private static final int COUNT_BITS = Integer.SIZE - 3;
// COUNT_MASK二进制数值:0001 1111 1111 1111 1111 1111 1111 1111
// 29个1,基本上是用来做位运算计算线程数量的
// 还有一点就是,这个数代表最大线程数,因为29个位置都是1
private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
// 下面的5个状态,只需要关注二进制的前3位即可
// RUNNING = 1110 0000 0000 0000 0000 0000 0000 0000
// -1的话,需要转换成补码才能向右移29位
private static final int RUNNING = -1 << COUNT_BITS;
// SHUTDOWN = 0000 0000 0000 0000 0000 0000 0000 0000
private static final int SHUTDOWN = 0 << COUNT_BITS;
// STOP = 0010 0000 0000 0000 0000 0000 0000 0000
private static final int STOP = 1 << COUNT_BITS;
// TIDYING = 0100 0000 0000 0000 0000 0000 0000 0000
private static final int TIDYING = 2 << COUNT_BITS;
// TERMINATED = 0110 0000 0000 0000 0000 0000 0000 0000
private static final int TERMINATED = 3 << COUNT_BITS;
// 计算c这个数值和1110 0000 0000 0000 0000 0000 0000 0000相与的结果,其实就是计算线程池的状态
private static int runStateOf(int c) { return c & ~COUNT_MASK; }
// 计算当前线程池的线程数量;c与0001 1111 1111 1111 1111 1111 1111 1111相与
private static int workerCountOf(int c) { return c & COUNT_MASK; }
// rs为线程状态,wc是线程数量;一般使用这个方法计算ctl值,也就是状态和数量共同值
private static int ctlOf(int rs, int wc) { return rs | wc; }
线程池对象初始化时执行ctlOf(RUNNING,0)返回一个int值作为ctl的初始化值。RUNNING是前3位全部为1,与0执行位运算|,这个0就是初始化的时候是0个线程,得到的结果如下。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static int ctlOf(int rs, int wc) { return rs | wc; }
- 添加任务
public void execute(Runnable command) {
// 添加的任务不能为空
if (command == null)
throw new NullPointerException();
// ctl是一个32位的整形值,前3为代表线程池的状态,后29位代表当前线程池中线程的数量
int c = ctl.get();
// workerCountOf(c)这个方法是通过位运算计算当前线程池线程数量;当线程数量小于核心线程数,那么执行添加工作线程的操作
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);
}
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
// 开启自旋;先获取线程池状态及数量
for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
// 如果c=[SHUTDOWN | STOP | TIDYING | TERMINATED]其中之一,并且c = [STOP | TIDYING | TERMINATED] 或者 任务不为空 或者等待队列为空,就返回false
//翻译成人话,就是
// 1.如果线程池的状态处于[STOP | TIDYING | TERMINATED]中,那么就直接创建失败
// 2.如果线程池的状态处于SHUTDOWN,并且任务不为空的话,那么也创建失败。
// 3.如果线程池的状态处于SHUTDOWN,并且等待队列为空,同样创建失败。
// 上述条件下,满足其一,都会创建新线程失败,走向拒绝策略。
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
// 走到这里,说明此刻线程池的状态处于RUNNING
for (;;) {
// 1.如果是创建核心线程,那么就比较一下当前线程数量是否大于等于核心线程数
// 2.如果是创建非核心线程,那么比较一下当前线程数是否大于等于最大线程数
// 如果上述条件确实满足,说明就不能创建工作线程了,那就要创建失败。
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
// 此时需要通过CAS的方式实现线程数+1,这个操作必须满足原子性。
if (compareAndIncrementWorkerCount(c))
// 如果自增成功,说明拿到了创建工作线程的通行证,那么就直接跳出双重循环,进入下一关去真正地创建工作线程。
break retry;
//没有拿到通行证的话,就好好地自旋
// 重新读取状态
c = ctl.get(); // Re-read ctl
// 如果当前状态处于[SHUTDOWN | STOP | TIDYING | TERMINATED]中,那么最终会返回false,创建工作线程失败
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// 否则重新内部自旋直至满足以下情况
// 1.线程数量超过限制,创建失败。
// 2.自增成功,拿到通行证,进入下一步创建工作线程
// 3.线程池状态发生变化,最终创建失败。
}
}
// 有通行证的才能执行到这里
// 下面新创建的工作线程是否开始运行的标识
boolean workerStarted = false;
// 下面新创建的工作线程是否被添加到工作线程集合中
boolean workerAdded = false;
Worker w = null;
try {
// 创建一个工作线程;
// 一个work绑定一个线程,创建work的同时,会创建一个对应的线程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 获取一个重入锁
final ReentrantLock mainLock = this.mainLock;
// 上锁;
//如果看不明白的话,就把这两行代码替换成synchronized (this)
mainLock.lock();
// 解锁前的逻辑都不存在线程安全的问题
try {
// 重新检查线程池状态
int c = ctl.get();
// 1.如果线程池状态位RUNNUING
// 2.如果线程池状态处于[RUNNING | SHUTDOWN],并且任务为null的情况
// 那么都可以把当前工作线程放进工作线程集合中
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
// 确保刚刚创建出来的线程没有还没有运行。其实就是没有执行start()方法。这种情况基本不存在。
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 把工作线程放进集合中。
// 这个集合是HashSet,在获取重入锁的情况下不存在线程安全问题。
workers.add(w);
// 计算当前线程集合中的数量
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
//修改是否添加进集合的标识
workerAdded = true;
}
} finally {
// 解锁
mainLock.unlock();
}
// 如果已经添加进集合中,那么开启线程
if (workerAdded) {
t.start();
// 设置工作启动标识
workerStarted = true;
}
}
} finally {
// 如果工作线程没有启动,那么
if (! workerStarted)
// 1.从集合中移除
// 2.线程数减1
// 3.尝试tryTerminate()终止操作,不一定会终止
addWorkerFailed(w);
}
// 返回新创建的工作线程是否启动的结果
// 工作线程成功启动也证明成功地创建新的工作线程。
return workerStarted;
}
// 1.如果线程池的状态处于[STOP | TIDYING | TERMINATED]中,那么就直接创建失败
// 2.如果线程池的状态处于SHUTDOWN,并且任务不为空的话,那么也创建失败。
// 3.如果线程池的状态处于SHUTDOWN,并且等待队列为空,同样创建失败。
// 上述条件下,满足其一,都会创建新线程失败,走向拒绝策略。
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
上述代码需要仔细解释一下。
- 首先如果线程池的状态处于[STOP | TIDYING | TERMINATED]中,是不能再创建新的线程了,也不会接受新的任务,直接走向拒绝策略
- 其次如果是处于SHUTDOWN状态的话,如果等待队列不为空的话,可以接受创建新的工作线程来帮忙,但是不能接受新的任务。
- 最后,如果处于SHUTDOWN状态,并且等待队列中没有任务的话,那么不接受创建新的线程,更不接受新的任务。
所以SHUTDOWN属于软关闭状态。
// 1.如果是创建核心线程,那么就比较一下当前线程数量是否大于等于核心线程数
// 2.如果是创建非核心线程,那么比较一下当前线程数是否大于等于最大线程数
// 如果上述条件确实满足,说明就不能创建工作线程了,那就要创建失败。
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
其实addWorker(Runnable firstTask, boolean core)这个core的作用就是用来确定是否是创建核心线程,根据这个值来间接判断对应的线程数量是否超标了。并且在后续创建工作线程的代码中并没有起到作用,所以可以判断,核心线程与非核心线程并没有本质上的差别,在创建工作线程时并不会标记某个线程是核心线程。
// 1.如果线程池状态位RUNNUING
// 2.如果线程池状态处于[RUNNING | SHUTDOWN],并且任务为null的情况
// 那么都可以把当前工作线程放进工作线程集合中
if (isRunning(c) || (runStateLessThan(c, STOP) && firstTask == null))
上面的代码强调两点:
- RUNNING状态可以创建工作线程和处理任务
-
SHUTDOWN状态,等待队列还有任务的话,只允许创建新的线程帮忙处理剩下的任务,不能添加新任务。
execute()方法基本分析完毕,下一篇分析Work这个类。