线程池提交
我们就按照平时使用的方式,从execute()这以execute这个方法为入口
public void execute(Runnable command) {
...
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
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
clt 是一个 AtomicInteger ,说明这个是一个并发访问的属性,这个属性类似于读写锁的 state
clt 将线程数量 和 线程池状态两个信息都存在这个变量里面,一方面达到了节省资源的目的
另一方面解决了 线程池数量 和 线程池状态 这个变量的修改的原子性问题,无需再单独的区进行 这两个变量的同步
简单的说这个变量被拆成了两半,最高三位表示线程池状态,其余29位都表示线程的个数
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
获取到这个c 之后,就调用了workerCountOf©,其实根据方法名也能看出来是取出线程池中的线程数量(workerCount)
如果线程池中的数量小于 corePoolSize ,那么就会addWorker 这里面就会开启新的线程去执行任务,然后就会跟新这个 c ,
因为添加线程就意味着ctl 这个值被改变了
来看看线程池如何 添加新的线程,进入addWorker()
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
//首先是获取到ctl
int c = ctl.get();
//获取到线程池的状态
int rs = runStateOf(c);
//这里介绍一下线程池的状态
// -1 0 1 2 3
//running shutdown stop tidying terminated
//这里不考虑其他的特殊情况,假设现在线程池状态正常 正在running,所以这个if 不会进
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//这里获取 workerCount
int wc = workerCountOf(c);
// CAPACITY 表示容量 wc 如果大于最大的容量当然始要 return false的
//
if (wc >= CAPACITY ||
//core 是传入的参数 就是true 所以这里的判断就是wc是否大于等于corePoolSize
//那么问题来了,明明前面判断过wc 应该是<corePoolSize ,但是不要忘记了这里是并发环境,这个值是会被其他线程修改的
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 使用cas 进行workerCount的增加
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); //上面进行了增加,这里就需要更行 c
if (runStateOf(c) != rs)//线程状态的改变,跟关闭有关系,先不考虑
continue retry;
}
}
boolean workerStarted = false;//线程开始工作的标识位
boolean workerAdded = false;//线程添加的标识位
//这里的Worker 请先看下文
Worker w = null;
try {
//创建一个Worker
// 里面会对firstTask和thread进行赋值,其中的thread,来自线程工厂生产的线程
w = new Worker(firstTask);
// 取出Worker 的thread
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
//上锁
mainLock.lock();
try {
//获取线程池状态//这里其实就是判断线程池是不是被关了,线程是不是还live
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// private final HashSet<Worker> workers = new HashSet<Worker>();
//将Worker 添加到workers ,这里面显然保存的都是线程池中的线程
workers.add(w);
int s = workers.size();
// 更新属性largestPoolSize
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;//修改标志位
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();//开启线程 见下文
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
t.start()
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
//见下文add(this)
group.add(this);
boolean started = false;
try {
start0();//!!! 真正去启动线程的地方,不多解释
started = true;//表示线程启动了
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
start0()
上面启动了start0()这个方法,线程真正的被启动了,所以那么任务是什么时候被执行的呢???
我们来到Worker 的run方法,下问有介绍Worker ,这个类本身就实现了 Runnable,所以启动的时候当然是执行run()
public void run() { runWorker(this);}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;//获取需要执行的任务,这个任务再创建线程的时候就已经传入进来了
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//task = getTask() 这里如果 task == null 那么就会从队列里面获取任务
while (task != null || (task = getTask()) != null) {
w.lock();//上锁
//这个是处理线程池stop 的情况,如果线程池停止,那么需要线程进行interrupted(),不做过多讨论
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
// beforeExecute,执行之前的操作,这里其实可以算是线程池提供的扩展点,如果我们需要实现自己的线程池可以重写这个方法
beforeExecute(wt, task);
Throwable thrown = null;
try {
//task 任务开始执行,注意这里调用的是run方法,不是start方法
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
//扩展点,类似beforeExecute
afterExecute(task, thrown);
}
} finally {
task = null;//任务执行完制空
w.completedTasks++;//完成任务的数量
w.unlock();
}
}
completedAbruptly = false;
} finally {
//Worker 退出相关
processWorkerExit(w, completedAbruptly);
}
}
add(this)
void add(Thread t) {
synchronized (this) {
//判断当前线程状态
if (destroyed) {
throw new IllegalThreadStateException();
}
//threads 的初始化
if (threads == null) {
threads = new Thread[4];
} else if (nthreads == threads.length) {//threads 的扩容
threads = Arrays.copyOf(threads, nthreads * 2);
}
threads[nthreads] = t;
nthreads++;//添加的下标
nUnstartedThreads--;//这个线程现在是正式成员了,减少未启动的线程数
}
Worker
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
final Thread thread;
Runnable firstTask;
volatile long completedTasks;
public void run() {
runWorker(this);
}
...
}
还记的添加线程的时候调用的是addWorker方法么,这个Worker 其实就是对Thread 一层封装,里面包装了 Thread 类型的属性
于此同时还实现了AQS,所以这个Worker其实也是一把锁,里面提供了Lock unLock等等关于锁的操作,这里注意Worker 还实现了implement ,至于为什么会实现这个接口,本文也会介绍