线程池的5种状态
// runState is stored in the high-order bits
//线程池处于RUNNING状态,既可以处理新任务,也可以处理阻塞队列中的任务
private static final int RUNNING = -1 << COUNT_BITS;
//线程池处于SHUTDOWN状态,不可以处理新任务,但可以处理阻塞队列中的任务,
private static final int SHUTDOWN = 0 << COUNT_BITS;
//线程池出域STOP状态,即不可以处理新任务,也不可以处理阻塞队列中的任务
private static final int STOP = 1 << COUNT_BITS;
//出域TIDYING状态时,线程池中的工作线程(workerCountOf)w为0
private static final int TIDYING = 2 << COUNT_BITS;
//由TIDYING自动流转到TERMINATED,可自定义扩展terminated()方法
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
//高位表示运行状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
//表示工作线程总数
private static int workerCountOf(int c) { return c & CAPACITY; }
//值c
private static int ctlOf(int rs, int wc) { return rs | wc; }
主体逻辑
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {//工作线程总数小于核心线程数,这里即使核心线程中有空闲线程,也会创建新线程,tomcat线程池会优先使用空闲线程
if (addWorker(command, true))//新增工作线程
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {//核心线程数已达到最大值,将任务入队,tomcat线程池会先将最大线程数创建出来在入队
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))//再次判断,若不是运行状态,则移除任务并执行拒绝逻辑
reject(command);
else if (workerCountOf(recheck) == 0)//若工作线程为0,创建线程执行任务,firstTask==null
addWorker(null, false);
}
else if (!addWorker(command, false))//入队失败,则判断是否能创建线程,这里是一个非公平的表现,队列中的老任务还是会等待空闲线程来执行,新线程只会执行新任务,创建失败则执行拒绝策略
reject(command);
}
添加工作线程
private boolean addWorker(Runnable firstTask, boolean core) {
retry://for循环取名
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
//不创建新的工作线程条件
//阻塞队列为空
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//工作线程总数
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))//工作线程根据core判断是大于corePoolSize还是最大线程数
return false;
if (compareAndIncrementWorkerCount(c))//通过cas增加工作线程总数
break retry;//增加成功跳出最外层循环
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)//状态发生变化,继续外层循环
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 rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
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)
addWorkerFailed(w);
}
return workerStarted;
}
线程worker的任务方法
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
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
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
//钩子方法,执行之前调用
beforeExecute(wt, task);
Throwable thrown = null;
try {
//执行真正的业务方法
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 {
//线程退出时,会执行这个方法,异常退出时 completedAbruptly = true,正常退出 completedAbruptly = false
processWorkerExit(w, completedAbruptly);
}
}
获取阻塞队列中的任务
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
//工作线程总数
int wc = workerCountOf(c);
// Are workers subject to culling?
//allowCoreThreadTimeOut:是否允许所有线程(包括核心线程,核心线程若空闲超时也会被剔除)空闲超时;当前工作线程大于核心线程数
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))//线程空闲超时
&& (wc > 1 || workQueue.isEmpty())) {//队列为空挥着工作线程大于1
//通过cas减少工作线程的数量
if (compareAndDecrementWorkerCount(c))
return null;//若返回空则线程不在等待阻塞队列的任务,线程退出
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();//获取任务
if (r != null)
return r;
timedOut = true;//超时未获取到任务,则会执行删除线程的逻辑,这个逻辑不区分核心线程或者非核心线程。
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
处理线程退出
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
//尝试执行terminate()方法,若工作线程数为0,执行
tryTerminate();
int c = ctl.get();
//线程池状态为runniNG,shutdown
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {//若正常退出,异常退出直接新增线程
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;//获取最小线程数,若允许核心线程超时,min==0
if (min == 0 && ! workQueue.isEmpty())//若工作队列不为空
min = 1;
if (workerCountOf(c) >= min)//工作线程大于最小线程,也不需要创建,工作线程小于最小线程时则需要创建
return; // replacement not needed
}
addWorker(null, false);//firstTask,表示线程的第一个任务(即新提交的任务),此处为null
}
}
线程池中新增线程情况
- 线程池中的线程数小于核心线程数,每次提交一个新任务时,都会创建一个新线程来处理
- 当阻塞队列满了,此时有新任务提交,如果线程池中的线程数小于最大线程,也会创建新线程来处理新任务(不是处理阻塞队列中的任务,非公平)
- 线程执行业务方法过程中出现异常。此时线程会退出,退出后会替补一个新线程加入到线程池中,这个新线程不处理新任务,而是等待阻塞队列中的任务
- 线程超时会正常退出,此时会有多个判断看是否创建线程
线程池中移除线程的情况
- 线程在等待队列任务时,等待超时,若满足线程剔除的条件(1.工作线程数大于当前核心线程数2.核心线程数是否允许超时)会被剔除掉
- 线程在执行业务代码时抛异常,此时线程会被剔除掉(线程为什么不重复利用?可能出于在线程异常时埋点,若不将异常抛出,此功能将不触发)
- 执行showtdown()或者shotdownNow()
showtdown()和shotdownNow()的区别
shutdown()
关闭线程池,将线程池的工作状态设置为SHUTDOWN,不可以接受新任务,但可以处理队列中的任务
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();//给空闲线程设置中断标记
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
shutdownNow()
关闭线程池,将线程池的工作状态设置为Stop,不可以接受新任务,也不可以处理队列中的任务
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();//将所有线程设置中断标记
tasks = drainQueue();//将任务队列中的线程出队
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
jdk的线程池与tomct线程池的差别
jdk的线程池判断线程是否空闲的逻辑:
Worker自身实现了cas逻辑,unlock()-->直接将state设置为0,lock是同过cas将state=0,设置为1,线程在执行任务前将state设置为0,获取到任务后通过cas将state设置为1,判断线程是否空闲时通过加锁,若能加锁成功,则表明该worker线程空闲。
//给空闲线程设置中断标记
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {//尝试加锁,判断空闲
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
tomcat的线程池中判断线程是否空闲的逻辑,内部重写Queue的offer入队逻辑:
内部维护一个submittedCount的变量,任务执行前submittedCount++,执行后submittedCount--
通过比较正在执行的任务数与线程池中的线程数,判断是否有空闲线程,有则直接入队,无需开启新线程
//we have idle threads, just add it to the queue
if (parent.getSubmittedCount() <= parent.getPoolSizeNoLock()) {
return super.offer(o);
}