目录
Worker类是定义在ThreadPoolExecutor中的内部类,要了解Worker,先要知道ThreadPoolExecutor是什么。
一,从ThreadPoolExecutor说起
ThreadPoolExecutor是JDK1.5加入的,用来生成线程池的类,并且使用execute(Runnable)或者submit()方法向线程池添加任务,比如这样:
static void test() {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
threadPoolExecutor.execute(() -> {
System.out.println("test ThreadPoolExecutor");
System.out.println(Thread.currentThread().getName());
});
threadPoolExecutor.execute(() -> {
System.out.println("test ThreadPoolExecutor");
System.out.println(Thread.currentThread().getName());
});
}
execute()方法在ThreadPoolExecutor类中有重写,当调用execute()方法时,ThreadPoolExecutor向线程池中添加了任务,并使用Worker类来处理任务,包括新建线程和任务处理等工作。
submit()方法在ThreadPoolExecutor中没有,实现方法在ThreadPoolExecutor的父类AbstractExecutorService中,而且有几个不同的方法重载:
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
可以看到submit()方法实际上是对任务进行了简单的封装,然后又调用了ThreadPoolExecutor的execute()方法,其中RunnableFuture类实现了Runnable接口。
二,Worker类的源码
Worker类是ThreadPoolExecutor中定义的内部类,其代码是这样的:
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
/**
* 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);
}
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
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(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
可以看到Worker类实现了Runnable接口,说明Worker本身也是一个任务,有run()方法,可以被执行。
Worker类主要维护了4个参数:
1,final Thread thread;
thread属性是Worker维护的线程,每个Worker对象一个,这个就是用来执行任务用的线程,也就是说,Worker对象的数量也就代表了线程池中活动线程的数量。
2,Runnable firstTask;
Worker对象的初始任务,多数情况下每个Worker对象创建时都伴随一个初始任务,是这个Worker对象优先会执行的任务,当执行完firstTask后,Worker对象还会从线程池中继续获取任务并执行。
3,volatile long completedTasks;
该Worker对象执行完成的任务数。
4,private static final long serialVersionUID = 6138294804551838833L;
序列化UID,没什么用,注释写的也很坦诚,用不上,加这个参数就是为了不想看到Java的警告。
三,execute()方法和新建Worker
Worker对象是在ThreadPoolExecutor执行execute()方法时产生的,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);
}
总的来说这个方法分了三步:
1,当前Worker数小于corePoolSize时,说明活动线程数没有达到允许的核心线程数上限,此时调用addWorker()方法。注意此时方法的第二个参数是true,代表本次添加Worker的前提是活动线程数不超过corePoolSize。
2,当前Worker数大于corePoolSize时,判断线程池是否是RUNNING状态,然后试图向workQueue中添加任务。添加任务成功后需要进行二次检查,如果线程池状态不是RUNNING则从workQueue中删除刚刚添加的任务,并且执行拒绝策略,另外如果活动线程为0则可以调用addWorker()方法新增一个无任务的Worker。
3,如果来到这一步,也就是Worker数大于corePoolSize,而且向workQueue中添加任务失败,则再次执行addWorker()方法。和第一步不同,此时调用addWorker()方法的第二个参数是false,代表本次添加Worker的前提是线程数不超过maximumPoolSize。这意味着这一步把线程池中的活动线程上限从corePoolSize提高到了maximumPoolSize。如果此时添加Worker失败,则执行拒绝策略。
以上是执行execute()方法时添加Worker的逻辑,下面看一下addWorker()方法的具体代码实现:
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
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))
return false;
if (compareAndIncrementWorkerCount(c))
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的情况,比如连接池状态是SHUTDOWN,或者活动线程数超过阈值,阈值根据参数是true或false决定是corePoolSize或maximumPoolSize。
第二部分开始正式新增Worker,初始化Worker对象:
w = new Worker(firstTask);
此处Worker的构造方法如下:
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
初始化Worker对象的同时新增了一个线程作为Worker的参数。
其中getThreadFactory()方法得到的是一个java.util.concurrent.ThreadFactory接口的实例,这个接口的newThread()方法:
Thread newThread(Runnable r);
传了一个Runnable参数,此处实际上是把Worker对象本身作为参数传入了newThread()方法,这种生成线程的方式,当执行线程的start()方法时,会调用参数(也就是Worker对象)的run()方法。
如果我们创建ThreadPoolExecutor时使用默认的ThreadFactory,也就是Executors.defaultThreadFactory(),使用的就是Executors类中的DefaultThreadFactory类,实现代码如下:
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
可以看到此类的newThread(Runnable r)方法,新建线程用的是:
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
其中参数r就是Worker对象,当执行线程的start()方法时,会调用Worker对象的run()方法。
至此Worker对象初始化完成。
四,Worker的run()方法
初始化Worker对象完成后,下面要启动Worker的线程,下面的代码使用了一个ReentrantLock锁,把初始化好的Worker对象加入workers列表,workers是ThreadPoolExecutor中定义的一个HashSet,如果添加成功,则调用Worker线程的start()方法,也就是这一段代码:
if (workerAdded) {
t.start();
workerStarted = true;
}
如前文所说,当调用t.start()方法时,会调用Worker的run()方法:
public void run() {
runWorker(this);
}
其中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 {
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 {
processWorkerExit(w, completedAbruptly);
}
}
此方法就是Worker执行线程池任务的方法,注意到其中while循环的条件:
while (task != null || (task = getTask()) != null)
其中task由firstTask赋值,或者由getTask()方法获得,可见,Worker线程首先执行自己的firstTask任务,执行完后再从线程池中获取任务来执行。
getTask()方法的源码后面有。
任务获取完成后继续回到runWorker(this)方法看Worker执行任务的流程,从任务一开始就调用了Work.lock()方法加锁,然后分别执行了:
beforeExecute(wt, task);
task.run();
afterExecute(task, thrown);
三个方法。
其中beforeExecute(wt, task)是个空方法,里面没有任何代码逻辑,是给我们自定义连接池的时候用的,我们可以自己定义一个连接池类,继承ThreadPoolExecutor,并重写beforeExecute(wt, task)方法。
task.run()方法就是执行任务的run()方法了。
afterExecute(task, thrown)是在执行完任务之后执行的方法,也是个空方法,等待开发者自己重写。另外,这个方法是写在finally里的,也就是说,即使在执行任务的时候因异常而中断,该方法也会执行。
循环的最后,把task设为null,增加Worker的完成任务数,并调用w.unlock();解锁,接着进入下一次循环,获取新的任务。
当线程池已经不再有任务需要执行,则调用:
processWorkerExit(w, completedAbruptly);
方法退出Worker线程,processWorkerExit()方法的代码:
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();
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
方法里又用了一个锁,锁中的内容是把Worker对象的完成任务数加到线程池的总完成任务数中,并从workers列表中移除这个Worker对象。
tryTerminate()方法的作用是尝试把线程池状态置为TERMINATED,以下两种情况可以设置成功:
1,线程池状态为SHUTDOWN,活动线程数为0,任务队列为空。
2,线程池状态为STOP,任务队列为空。
其中修改状态的操作有加锁且为CAS操作。
tryTerminate()方法之后,如果当前活动线程数小于核心线程数,而且线程池还没有被关,则新建一个Worker,这个Worker没有初始任务。
至此runWorker()方法完成。
另外单独关注一下runWorker()方法中,用于获得任务的getTask()方法的代码:
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?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
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;
}
}
}
在getTask()方法中,首先判断连接池状态,如果状态已经是STOP,或者SHUTDOWN状态但任务队列没有任务了,那就不用再获取任务了,而且这种状态下线程池也不可能再新增任务,所以尝试减少Worker线程数量,也就是这段:
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
接下来定义了一个boolean参数timed,用来判断Worker将会用哪种方式来获取任务:
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
allowCoreThreadTimeOut代表核心线程是否需要考虑获取的超时时间,默认是false,后面的wc > corePoolSize代表活动线程数是否大于核心线程数的阈值,原则上如果活动线程数大于核心线程数,从队列获取任务时需要考虑超时时间。
如果timed为true,表示需要考虑超时时间,使用poll的方式,否则会用take的方式获取任务,take方法在队列为空时会阻塞线程。
以上