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);
}
addWorker(添加线程):
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
先看addWorker方法的第一部分,这个方法弄懂了,execute方法就非常好理解:
先讲大致意思:
首先一进来方法,就是两个死循环:
for(int c =ctl.get();;){
for(;;){
...
}
}
而唯一跳出死循环的办法就在第四步:
break retry;
可能很多人不理解为什么break要这么写,这其实就是标志位的写法,很多源码中都能看到
详情参考链接:java retry: 详解
所以break retry
的含义就是 跳入到标志位处,且不再进入标志位下方的循环
continue retry
:跳入到标志位处,跳过本次循环,进入下次循环
我们再来看看方法块中成员变量ctl
及方法runstateAtleast()
、compareAndIncrementWorkerCount()
成员变量ctl
源码中简单说明了ctl是一个成员变量,主要作用是记录线程池的生命周期状态
和当前线程数
,ctl是原子性的,作者通过巧妙的设计,将一个整形变量按二进制分为两部分,也就是说ctl中的成员变量value
通过拆装箱
可以表达两种含义
(线程池的生命周期状态、当前线程数),想了解更深的可以参考链接(反正我是看不懂):详解Java线程池的ctl(线程池控制状态)【源码分析】
线程池的声明周期状态:
拆装箱方法详解:线程池(二、ctl 的设计分析)
runStateAtLeast()
字面意思:线程池状态大于等于xx
来看这个方法使用:
runStateAtLeast(ctl.get(), SHUTDOWN))
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
ctl.get():就是获取ctl的成员变量value,之前也说到成员value是可以表达两种含义的(线程池的生命周期状态、当前线程数),这里就有用到表达声明周期状态的用法。
SHUTDOWN
是有初始化的,所以方法可以简单理解成:若当前ctl的生命周期状态>=SHUTDOWN
,就证明当前线程池的生命周期状态是SHUTDOWN状态或者是其它状态,但绝不是RUNNING状态,线程池初始化的五种状态,值越大就代表当前线程池就越危险。
workerCountOf()
获取当前线程池的已有的线程数量。
compareAndIncrementWorkerCount©
/**
* Attempts to CAS-increment the workerCount field of ctl.
*/
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
/**
* Atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expectedValue, int newValue) {
return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
}
将当前ctl的value值加1,可以理解成当前线程数量+1
直接执行任务了,并没有交给阻塞队列
。Worker
Woker就是线程池的内部类,构造方法就是调用线程工厂新建线程
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
/**
* Returns the thread factory used to create new threads.
*
* @return the current thread factory
* @see #setThreadFactory(ThreadFactory)
*/
public ThreadFactory getThreadFactory() {
// 返回当前线程池的线程工厂
return threadFactory;
}
这里可能大部分不会理解,为什么在第二步加入阻塞队列之后还需要再判断有没有线程、线程池状态,这里因为在创建线程池的时候,核心线程大小个数可能会被设置成0,若是设置为0,则可以跳过第一步的判断,若是没有第四步则会导致任务都会进入阻塞队列,但是却没有线程执行任务
。
核心线程数大小
,小于则新建线程并直接执行任务