一.目的
Worker用于执行任务。
顺便了解下线程池状态流:
running可以通过shutdown方法到shutdown状态,然后之后会变成tidying状态,最后变成terminate状态。
通过shutdownNow方法,则状态直接变成:stop,然后变成tidying状态,最后变成terminate状态。
。
shutdown方法,不会接收新任务,但会等待处理完任务队列中的任务再结束线程池。
shutdownNow比较粗暴,不会接收新任务,如果有任务在执行会强制中断它,然后把任务队列中的任务返回给调用方,这里就要根据业务是否允许强制中断来分析风险点。
worker为了不消耗大量cpu,会阻塞,底层是blockingQueue的阻塞获取机制。
二.基础知识
Worker在第一次创建时,会先执行传入的task,之后会从任务队列中取。
多个worker在ThreadPoolExecutor中存储是一个hashset。
Worker数据结构:
final Thread thread;//执行线程
Runnable firstTask;//第一个任务
volatile long completedTasks;//当前worker已经完成的任务数
Worker继承于AQS。
核心方法是:【runWorker(Worker w) 】
基本逻辑分为:
1.如果是创建时执行,有firstTask则执行这个任务。否则从任务队列中获取
while (task != null || (task = getTask()) != null)
getTask())用于获取任务。后面会详细说明。
2.检查当前线程池状态,如果是stop(shutdownNOW方法触发),并且线程状态中断标记未设置,则设置中断位
3.执行beforeExecute方法,默认实现为空,主要是ThreadPoolExecutor交给子类去实现一些个性化逻辑
4.执行任务run方法,这里业务任务发生异常,这个worker线程会被释放。并且会如果当前线程数已经小于核心线程数则会再创建一个worker
5.执行afterExecute对错误信息可以进行特殊处理
方法代码如下:
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(); //这里的lock很重要,因为在shutdown线程池时会中断相应worker,这里加lock可以保证任务执行的原子性,防止任务执行一半,导致业务数据的不一致。
//如果线程已经处于stop并且线程中断位未设置,则设置线程中断位。中断位需要业务任务自己去检测使用。
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;//这个标记用于区分是异常或者中断,还是正常因为线程要回收等情况。前者异常需要在执行后面processWorkerExit方法,减少worker线程数的逻辑。
} finally {
processWorkerExit(w, completedAbruptly);//出现异常,或者当前线程池被关闭都会走到这个方法
//processWorkerExit主要是用于worker退出后做资源释放及相应是否需要新增worker的逻辑。
}
}
processWorkerExit方法逻辑:
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
//移除这个worker,之后这个对象会被垃圾回收,线程也会被回收
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
//尝试将线程池状态设置成terminate,能够设置的条件是:当前线程池状态是shutdown并且任务队列无任务或stop状态
//如果当前可设置成terminate状态,并且还有worker线程存在,则中断它
//然后设置线程池状态为TIDYING:到达这个状态则说明当前线程数为0了,并且整个线程池已无任务。
//最后加锁执行terminate方法。这里是空方法,子类可以实现特列逻辑。
tryTerminate();
int c = ctl.get();
//下面的代码主要是看是否需要创建新的worker用于替换这个释放掉的worker
//两种情况会需要创建新的worker。
//1.当前被释放的worker由于异常代码
//2.当前是正常退出(由于之前线程超过核心线程数或者由于超过最大线程数,或者是检测到了shutdown信号)
//然后发现这时发现还有任务待执行,则创建一个worker
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
//当前线程池未关闭。处于running或shutdown状态。并且是正常因为
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
//worker线程已经超过核心线程数就不需要再创建worker了
return; // replacement not needed
}
addWorker(null, false);//创建worker,底层还是会根据线程池及是否有任务等情况看是否需要创建
}
}