1、5种状态
//线程池能够接受任务,并且可以运行队列中的任务
private static final int RUNNING = -1 << COUNT_BITS;
//不接受新的任务,但是之前队列里面的任务还是会被调用[shutDown()之后的状态]
private static final int SHUTDOWN = 0 << COUNT_BITS;
//不接受新的任务,不会执行队列中的任务,并且尝试去中断正在运行的任务[shutDownNow()之后的状态]
private static final int STOP = 1 << COUNT_BITS;
//所有任务都已经终止,workCount值为0(workCount可以理解成线程的个数)转到TIDYING状态的线程即将要执行terminated()钩子方法
private static final int TIDYING = 2 << COUNT_BITS;
//terminated()方法执行结束
private static final int TERMINATED = 3 << COUNT_BITS;
2、5种状态的转换
RUNNING -> SHUTDOWN:调用了shutdown()方法,或者线程池实现了finalize方法,在里面调用了shutdown方法。
(RUNNING or SHUTDOWN) -> STOP:调用了shutdownNow方法
SHUTDOWN -> TIDYING:当队列和线程池均为空的时候
STOP -> TIDYING:当线程池为空的时候
TIDYING -> TERMINATED:terminated()钩子方法调用完毕
3、线程池/任务队列,区别
/**这个workers可以理解为真正的线程池,对它的操作都要通过mainLock上锁,操作完毕解锁
* Set containing all worker threads in pool. Accessed only when holding mainLock.
*/
private final HashSet<Worker> workers = new HashSet<>();
4、构造器
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0) throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;//核心线程个数
this.maximumPoolSize = maximumPoolSize;//最大线程个数 最大线程个数要大于核心线程个数
//线程池任务队列(线程池关键地方,有时候注重任务出队的顺序或者任务有优先级都要靠他来实现)
this.workQueue = workQueue;
//核心线程之外的线程如果达到了这个空闲时间线程自动关闭(可以通过allowsCoreThreadTimeOut()作用于核心线程)
this.keepAliveTime = unit.toNanos(keepAliveTime);
//线程工厂用来创建线程的,用于设置线程的优先级,名字,debug等
this.threadFactory = threadFactory;
//对reject的任务的处理(当workQueue满了并且达到了最大线程的个数时,或者调用了shutdown函数之后,再加入任务也是会reject的)
this.handler = handler;
}
5、submit(...)在父类中(AbstractExecutorService)实现的,
ThreadPoolExecutor源码笔记(一)
1)把传入的Runnable、Callable等数据组装成FutureTask ThreadPoolExecutor源码笔记(二)
2)调用execute(Runnable)执行FutureTask
6、execute(Runnable command)
1)活动线程小于corePoolSize的时候创建新的线程,活动线程大于corePoolSize时都是先加入到任务队列当中
调用addWorker方法时会原子性的检测runState、workerCount,达到线程池上限时触发拒绝策略,返回false
addWorker方法第一个参数是任务,第二个参数表示是否核心线程
2)如果任务成功添加到任务队列中,在执行任务前还是要再次检测线程池状态,如果状态非RUNNING,从队列中移除该任务并触发拒绝策略
如果线程池线程数为0(没有指定核心线程数),会创建新的线程执行addWorker方法【参数二:是否核心数为上限】
3)如果任务无法添加到队列,会用核心线程之外的线程处理任务addWorker,如果执行失败,说明线程池shutdown或者饱和了,触发拒绝策略
public void execute(Runnable command) {
if (command == null) throw new NullPointerException();
//ctl是AtomicInteger,线程安全的。唠叨一句,AtomicInteger内部也是通过Unsafe.java来实现同步的。
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {//小于核心线程数
if (addWorker(command, true))//第二个参数true,表示是使用corePoolSize作为上限
return;//活动线程小于corePoolSize,不会走下面的逻辑了
c = ctl.get();
}
//活动线程>=corePoolSize,先添加到workQueue中
//offer()往队列中添加任务,成功返回true,满了返回false
if (isRunning(c) && workQueue.offer(command)) {//线程池是RUNNING状态,且成功添加任务到队列
int recheck = ctl.get();
if (!isRunning(recheck) && remove(command))//又判断下线程池状态,非RUNNING,从队列移除该任务,然后调用reject(task)
reject(command);
else if (workerCountOf(recheck) == 0)//线程池处于RUNNING状态 || 线程池处于非RUNNING状态但是任务移除失败
/*
* 这行代码是为了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。
* 添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务,该方法会创建新的线程,从队列中获取任务并执行。
*/
addWorker(null, false);
}
else if (!addWorker(command, false))//非RUNNING状态拒绝新的任务 || 队列满了启动新的线程失败(workCount > maximumPoolSize)
reject(command);
}
7、Worker
内部类Worker是对任务的封装,所有submit的Runnable都被封装成了Worker,它本身也是一个Runnable,
然后利用AQS(AbstractQueuedSynchronizer)实现了一个简单的非重入的互斥锁,实现互斥锁主要目的是为了中断的时候判断线程是在空闲还是运行。
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread;//执行任务的线程
Runnable firstTask;//要执行的具体任务
volatile long completedTasks;//该线程执行完成的任务数
/**
* 通过传入的第一个task和线程工厂创建的线程,创建一个Worker对象,task可为null
*/
Worker(Runnable firstTask) {
setState(-1); //在调用runWorker()之前禁止中断 inhibit interrupts until runWorker
this.firstTask = firstTask;
//ThreadFactory默认是Executors.DefaultThreadFactory.java
this.thread = getThreadFactory().newThread(this);//通过传入的/默认的线程工厂创建一个线程
}
//一被线程调用,就触发这个run()方法
public void run() {
runWorker(this);//调用ThreadPoolExecutor.runWorker(Worker)执行该任务
}
//是否独占状态,state != 0,表示锁定状态/独占状态
protected boolean isHeldExclusively() {
return getState() != 0;//state值为0:表示解锁状态,为1:表示锁定状态
}
/**
* 如果state为0(解锁状态),则state改为1(锁定状态),并设置当前线程为独占模式同步所有者
* 其实就是申请同步锁定,返回锁定结果,成功true,失败false
*/
protected boolean tryAcquire(int unused) {
//这里又用到Unsafe.CAS做线程安全的比较与更新
if (compareAndSetState(0, 1)) {//如果state为0,返回true并赋值为1;否则返回false
//调用的AbstractQueuedSynchronizer的api,设置当前线程为独占模式同步的所有者
setExclusiveOwnerThread(Thread.currentThread());
return true;//成功获得锁
}
return false;
}
/**
* state只有0和1,互斥
* 解锁,设置独占模式同步所有者置为null,state改为0(解锁状态)
*/
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
//中断已经开始的任务,showDownNow()时终止所有线程,会调该方法
void interruptIfStarted() {
Thread t;
//由于state初始化时为-1,所以runWorker()之前,thread是不会被interrupt()的
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
8、addWorker(Runnable task, boolean isCore)
/**
* @param firstTask 第一个任务,可以为null。addWorker()时,会新增一个线程,去任务队列获取任务执行
* 所以execute()中有一个addWorker(null, false),用来新增一个线程去执行剩余的任务
* @param core 是否以corePoolSize作为上限
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry: for (;;) {//重试循环
int c = ctl.get();
int rs = runStateOf(c);//运行状态
/*
* 这条语句等价:rs >= SHUTDOWN && (rs != SHUTDOWN || firstTask != null || workQueue.isEmpty())
* 满足下列条件则直接返回false,线程创建失败:
* rs > SHUTDOWN: STOP || TIDYING || TERMINATED 此时不再接受新的任务,且所有任务执行结束
* rs = SHUTDOWN: firtTask != null 此时不再接受任务,但是仍然会执行队列中的任务
* rs = SHUTDOWN: firtTask == null && workQueue.isEmpty() 见execute方法的addWorker(null, false)
*
* 最后一种情况: SHUTDONW状态下,如果workQueue不为空继续往下执行
* execute()只有workCount==0的时,addWorker(null, false),firstTask才会为null。
* 也就是说线程池SHUTDOWN了不再接受新任务,但是此时workQueue队列不为空,那么还得创建线程把任务给执行完才行。
*/
if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())) {
return false;
}
/* 1)线程池状态为RUNNING
* 2)线程池状态为SHUTDOWN,但是任务队列还有任务未执行
*/
for (;;) {//又是死循环
int wc = workerCountOf(c);//任务数量
/* 1)wc >= CAPACITY: runState > SHUTDOWN || runState == SHUTDOWN && workQueue.isEmpty(),不再新增线程
* 也就是说,runState == SHUTDOWN && workQueue.isEmpty()是可以新增线程去执行队列中的任务的
* 2)后一段判断: wc(任务数量)达到线程池上限时,不在新增线程
*/
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))//线程安全递增workCount
break retry;//跳出外层的重试循环
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)//线程池的状态发生变化,则重试
continue retry;
// else CAS failed due to workerCount change; retry inner loop
//最后compareAndIncrementWorkerCount操作失败的话,重新跑内层循环
}
}
// wokerCount递增成功
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);//创建worker对象
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
//并发的访问线程池workers对象加锁
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
//RUNNING状态 || SHUTDONW状态下清理队列中剩余的任务
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) //线程还在使用中,那就没法执行worker了,非法线程状态
throw new IllegalThreadStateException();
workers.add(w);//任务添加到workers里,workers是个HashSet
int s = workers.size();
if (s > largestPoolSize)
//largestPoolSize用来记录线程池达到过的最大大小
largestPoolSize = s;
workerAdded = true;
}
} finally {//任务添加到workers后释放锁
mainLock.unlock();
}
if (workerAdded) {//任务添加成功后,启动线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)//线程启动失败,移除线程池中对应任务,任务计数器-1
addWorkerFailed(w);
}
return workerStarted;
}
//添加任务失败时,从线程池中移除worker,workerCount-1,同样有锁操作
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//移除之前上锁
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {//结束之后解锁
mainLock.unlock();
}
}
9、runWorker(Worker ..)
runWorker()是在Worker.run()中触发的,也就是在执行任务的子线程中触发任务添加成功后,启动线程,真正执行的是runWorker(Worker)。
runWorker是线程池的关键,一个线程一旦进入runWorker就很难停下来了
while (task != null || (task = getTask()) != null) {}
执行完一个任务后,会继续从workQueue里去拿,一直执行下去。无任务时通过workQueue.take()保活
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();//此时的当前线程,就是执行该任务的子线程
Runnable task = w.firstTask;
w.firstTask = null;//引用置空
//Worker的构造函数中setState(-1)禁止线程中断,所以这里需要unlock允许中断
w.unlock(); // allow interrupts
/*用于标识是否异常终止,finally中processWorkerExit的方法会有不同逻辑
*为true的情况:1.执行任务抛出异常;2.被中断。*/
boolean completedAbruptly = true;
try {//如果getTask返回null那么getTask中会将workerCount递减,如果异常了这个递减操作会在processWorkerExit中处理
while (task != null || (task = getTask()) != null) {
w.lock();//禁止中断
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
//如果线程池STOP/TIDYING/TERMINATED,而当前线程未中断,则中断线程
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
&& !wt.isInterrupted())
wt.interrupt();
try {
//任务执行前操作,子类重载该方法
beforeExecute(wt, task);
Throwable thrown = null;
try {
//真正执行任务 task其实就是FutureTask,上一篇说过。futureTask.run()->callable.call()
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 {
//任务执行后操作,子类重载
afterExecute(task, thrown);
}
} finally {
task = null;//引用置空
w.completedTasks++;//该任务执行次数计数器
w.unlock();//解锁,允许中断
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);//任务执行完毕后,清理线程池中数据
}
}
10、getTask()
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
/* 1)rs >= STOP 此时不再处理任务队列中的任务
* 2)rs == SHUTDONW && workQueue.isEmpty 此时队列中已经没有任务,也就不用处理任务了
*/
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
/*getTask在runWorker中执行的,执行前worker添加到线程池中时计数器有递增
*此处返回null后该任务的执行线程就结束了所以计数器要workCount-1*/
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
//如果设置了允许核心线程闲置超时 || 任务数超过核心线程数,就是有时间限制了
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;//是否有超时限制
/* 1) workCount > maximumPoolSize
* 2) timed && timedOut && (除了本任务外,还有其他任务在执行||任务队列已经没任务了)
* 任务队列没任务,自然不需要再循环了。
*/
if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))//workCount-1
/* 有超时限制时,循环走到这里线程就结束了
* 无超时限制,线程数大于线程池最大线程数,循环走到这里线程也结束
*/
return null;//结束本线程
continue;//保留线程
}
/* 1)线程执行任务完成后触发processWorkerExit,该方法内部在RUNNING/SHUTDONW状态时,会addWorker(null,false)
* 也就是执行完之后线程池还活着,就再丢一个新线程进去,然后旧的线程就彻底结束了
* 2)这个新丢进来的线程进来时,发现workCount <= corePoolSize && 无超时限制 && RUNNING状态
* 那么会走到这一步,通过workQueue.take()保活,实现维持线程池核心线程数。
*/
try {
/* 1)有超时限制:指定超时时间从队列中取任务
* 2)无超时限制:workQueue.take(),BlockingQueue,队列为空时阻塞,从而保证线程池核心线程一直存在
*/
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;//线程被中断,重复循环
}
}
}
11、processWorkerExit //线程退出会执行这个方法做一些清理工作
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) //默认为true,runWorker正常结束时会设置为false,否则就是异常
decrementWorkerCount();//任务执行异常时workCount-1
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);//移除work,正常/异常,执行完都会remove
} finally {
mainLock.unlock();
}
tryTerminate();//尝试停止线程池
int c = ctl.get();
if (runStateLessThan(c, STOP)) {//还是RUNNING/SHUTDONW状态
if (!completedAbruptly) {//正常执行完任务的处理
//min是线程池最小闲置线程数,允许core超时,min为0,否则为corePoolSize
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;//min为0,但是任务队列还有任务没执行,要留一个线程来执行队列中任务
//workCount大于最小闲置线程数,该线程结束后不需要addWorker(null,false)补充线程
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);//workCount < min,线程池中线程低于最小闲置线程数,要补充线程。
}
}
12、tryTerminate
final void tryTerminate() {
for (;;) {
int c = ctl.get();
/*1)RUNNING状态,还要继续执行任务,不能停止线程池
*2)SHUTDOWN&&workQueue.notEmpty:虽然SHUTDOWN了,但是还有任务啊哟执行,不能停止线程池
*3)runState >= TIDYING:已经或者正在停止中,当然就不需要重复去停止了*/
if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//到这里还剩下 SHUTDONW&&workQueue.isEmpty 、STOP这两种状态
if (workerCountOf(c) != 0) { //还有任务没执行完
//只中断一个闲置线程,发出中断信号,中断阻塞在获取任务的线程
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {//设置为TIDYING状态
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();//给子类重载
} finally {
//设置为TERMINATED状态
ctl.set(ctlOf(TERMINATED, 0));
/* Condition termination = mainLock.newCondition()
* ThreadPoolExecutor中有个awaitTermination(),内部调用termination.awaitNanos(time)等待线程终止,
* 唤醒调用了 等待线程池终止的线程
* 唤醒所有等待线程池终止这个Condition的线程
*/
termination.signalAll();//继续awaitTermination ???
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
13、shutdown、shutDownNow、reject
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);//设置为SHUTDOWN,如果已经至少是这个状态那么则直接返回
//中断闲置线程,SHOUTDOWN状态只是中断闲置线程,保证剩余任务能继续执行
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);//设置为STOP,不接受新任务,不执行剩余任务
interruptWorkers();//中断所有线程,这个调用的是work.interruptIfStarted()
tasks = drainQueue();//返回队列中还没执行的任务
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {//遍历线程池(work池)
Thread t = w.thread;
/* w.tryLock能获取到锁,说明该线程没有在运行,因为runWorker中执行任务会先lock,
* 保证了中断的肯定是空闲的线程。*/
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)//onlyOne只中断一个线程
break;
}
} finally {
mainLock.unlock();
}
}
final void reject(Runnable command) {
handler.rejectedExecution(command, this);//拒绝处理,默认只是抛出RejectedExecutionException异常
}
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
//只是抛出RejectedExecutionException异常而已
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
}
}
总结:
1)workQueue存放要执行的任务Runnable。workers存放的worker,worker包含任务Runnable和执行该任务的线程Thread
2)线程池工作原理:3)执行任务,未超过核心线程数时,任务添加到workers线程池中,用核心线程直接执行任务;
超过核心线程数时,任务添加到workQueue任务队列中,通过addWorker(null,false),
创建线程(new Worker()默认会创建一个线程)从workQueue中取任务来执行
4) 线程池如何维持核心线程数
c:这个新丢进来的线程进来时,发现 workCount <= corePoolSize && 无超时限制 && RUNNING状态
那么会到任务队列中取,通过 workQueue.take()保活,实现维持线程池核心线程数。
d:线程池保活的关键在 runWorker(),该方法内部一个while循环,执行完当前任务后,会继续去workQueue里去取出来执行,直到取不到任务时,判断是否需要保活,需要保活的调用的是workQueue.take()。workQueue.take()取元素时有通过ReentrantLock.lock()/unlock();而通过锁阻塞线程保活的原理看这里!
e:没增加一个任务,如果线程数没达到最大线程数限制,会默认添加一个线程
参考资料:谢谢原作者
https://segmentfault.com/a/1190000010353461