开发中经常会使用到线程池,线程池也是Java中一个比较重要的概念,下面是对这两天阅读ThreadPoolExecutor源码的一点总结,只是总结了大致的轮廓,里面的细枝末节还没有完全弄明白,里面涉及到的东西还比较多,这里先做一个阶段性的总结。
下面是一个简单的线程池使用案例:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThreadPol {
static class Runner implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " : Hello, I'm a thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
}
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(5,20,
0, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(5));
for(int i = 0; i < 20; ++i) {
pool.execute(new Runner());
}
pool.shutdown();
}
}
每个线程的任务都是打印一句话,然后休息1s。
一次可能的输出如下:
可以看到线程池产生的最大线程数量是15个。使用线程池的好处就不说了,下面我们着重看看ThreadPoolExecutor中是怎么实现线程池的,了解了它的实现原理后,就可以更加自由的使用它了。
首先看看它提供了那些构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
可以看到,ThreadPoolExecutor类一共提供了4个public构造函数,且其余3个都是调用最后一个构造函数,下面我们先来分析这些参数的意义是什么。
corePoolSize:核心线程数的大小,默认表示线程池中一直保持活跃的最大线程数,即使没有任务了。可以设置allowCoreThreadTimeOut为true,这样如果没有任务了,核心线程数也会被注销。
maximumPoolSize:最大线程池大小,表示线程池中允许的最大线程数。当线程池中的线程数大于等于核心线程数且小于最大线程数,且工作队列已满,再来新的任务时,就会创建一个线程处理该任务。实际上最大的线程大小为min(2^19-1,maximumPoolSize)。原因后面会说明。
keepAliveTime,unit:这两个参数表示非核心线程数在没有任务的时候最大的存活时间,unit表示单位,可以是秒或者天等等。如果设置allowCoreThreadTimeOut为true的话,核心线程在该时间段内没有任务的话也会被注销。
workQueue:工作队列,这是一个阻塞队列。当队列为空时,从队列中取任务会被阻塞。如果workQueue设置为无界队列,那么maximumPoolSize的值就没有意义了,因为任务可以无限的添加到工作队列中,此时线程池中最大的线程池个数就是核心线程数。
threadFactory:用于实例化一个线程对象。
handler:当线程池无法处理任务时(工作队列满了,线程池中的线程数达到maximumPoolSize时)的策略,默认是抛出异常。
下面再看其主要的成员变量:
public class ThreadPoolExecutor extends AbstractExecutorService {
// 实例变量,原子变量。记录每个线程池的状态和线程池的大小,前3位表示状态,后29位表示线程数大小,所以最大的线程数是2^29-1
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // 1110 0000 0000 0000 0000 0000 0000 0000
private static final int COUNT_BITS = Integer.SIZE - 3; // Integer.SIZE = 32 COUNT_BITS = 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 1 1111 1111 1111 1111 1111 1111 1111 这个值表示最大线程数
//5种状态
private static final int RUNNING = -1 << COUNT_BITS; // 1110 0000 0000 0000 0000 0000 0000 0000
private static final int SHUTDOWN = 0 << COUNT_BITS; // 0000 0000 0000 0000 0000 0000 0000 0000
private static final int STOP = 1 << COUNT_BITS; // 0010 0000 0000 0000 0000 0000 0000 0000
private static final int TIDYING = 2 << COUNT_BITS; // 0100 0000 0000 0000 0000 0000 0000 0000
private static final int TERMINATED = 3 << COUNT_BITS; // 0110 0000 0000 0000 0000 0000 0000 0000
// 得到线程池状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 得到线程池中线程池的数量
private static int workerCountOf(int c) { return c & CAPACITY; }
// 根据线程池状态和线程池中线程的个数组合成一个int型变量
private static int ctlOf(int rs, int wc) { return rs | wc; }
// 判断线程池状态
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
// 增加workerCount的值,也就是线程池中线程的大小
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
// 减少workerCount的值
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
// CAS 减少workerCount的值
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
// 阻塞队列
private final BlockingQueue<Runnable> workQueue;
// 全局锁
private final ReentrantLock mainLock = new ReentrantLock();
// 工作线程 Worker进一步封装了Thread
private final HashSet<Worker> workers = new HashSet<Worker>();
// 等待条件
private final Condition termination = mainLock.newCondition();
private int largestPoolSize; // 记录线程池中出现过的最大线程数
private long completedTaskCount; // 记录已经完成的任务数
private volatile ThreadFactory threadFactory; // 线程工厂,用于生产线程,可以给线程指定有意义的名字
private volatile RejectedExecutionHandler handler; // 拒绝处理器
private volatile long keepAliveTime; // 超过核心线程数的空闲线程最大的存活时间
private volatile boolean allowCoreThreadTimeOut; // 核心线程在没有任务时是否被注销,默认是false
private volatile int corePoolSize; // 核心线程数
private volatile int maximumPoolSize; // 最大线程数
private static final RejectedExecutionHandler defaultHandler = // 默认的拒绝处理器,直接抛出异常
new AbortPolicy();
}
下面再看一下ThreadPoolExecutor类的内部类Worker,它是对线程Thread的进一步封装:
private final class Worker // 对线程的进一步封装
extends AbstractQueuedSynchronizer
implements Runnable // 内部类Worker实现了Runnable接口
{
private static final long serialVersionUID = 6138294804551838833L;
// 封装了一个线程对象
final Thread thread;
// 实际的任务
Runnable firstTask;
// 完成的任务数量
volatile long completedTasks;
Worker(Runnable firstTask) {
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); // public Thread newThread(Runnable r); Worker实现了Runnable接口,通过线程工厂生成一个Thread对象
}
// 实现Runnable 接口定义的方法
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() == 1;
}
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(); }
}
Worker类后面的一些方法,我也还没有彻底弄懂,为了完整性都将它们贴出来了,以后会再进一步解读的。
我们看到Worker类里面封装了线程对象Thread与任务firstTask。run方法的实现是调用了runWorker函数,我们再来看看runWorker的源码:
final void runWorker(Worker w) {
Runnable task = w.firstTask; // 取第一次任务firstTask
w.firstTask = null;
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) { // 每个Worker都在循环的接收任务
w.lock();
clearInterruptsForTaskRun();
try {
beforeExecute(w.thread, task); // 回调函数,子类继承实现自己的逻辑,在任务执行前调用
Throwable thrown = null;
try {
task.run(); // 最终还是执行的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++; // worker完成的任务数加1
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly); // 最后才执行到这里,进行最后的清理工作。之前一直在while循环里,不停的从工作队列中取任务
}
}
当firstTask执行完后,worker通过getTask()函数不停的取任务。beforeExecute(w.thread, task)与afterExecute(task, thrown);有点AOP的意思在每个任务开始前与结尾后调用,在ThreadPoolExecutor中是空函数体,子类可以重写实现自己的逻辑。下面我们顺藤摸瓜继续看看getTask()的源码:
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 当线程池工作状态为SHUTDOWN且工作队列为空时或者线程池的状态为STOP时worker就取不到任务了
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount(); // 减少工作线程数
return null; //如果返回ull了,就会执行processWorkerExit(w, completedAbruptly)它将执行清理工作,注销当前worker
}
boolean timed; // Are workers subject to culling?
for (;;) {
int wc = workerCountOf(c);
timed = allowCoreThreadTimeOut || wc > corePoolSize;
if (wc <= maximumPoolSize && ! (timedOut && timed))
break;
if (compareAndDecrementWorkerCount(c))
return null;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
try {
/*
如果timed为true [timed = allowCoreThreadTimeOut || wc > corePoolSize;]
那么将执行 workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) 在指定的时间内取不到任务,将会返回null,
返回null将导致该worker被清除,如果为false,将执行workQueue.take(),将会一直阻塞。
*/
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
// 从上面可以看到,如果设置了allowCoreThreadTimeOut为true,或者线程数大于corePoolSize后,线程在指定时间内没有取到任务就会被注销
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
下面就是最重要的函数了: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)) { // 如果线程池的状态是RUNNING并且新进来的任务成功地被添加进了阻塞队列中
// 因此,如果这里使用的是无界队列的话,新进来的任务会被一直添加到阻塞队列中,那么最大线程数的设置就没有用了
int recheck = ctl.get(); // 下面是对线程池状态的进一步判断
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false)) // 添加进阻塞队列失败后,调用addWorker(),这里的第二个参数为false,表示该线程不是核心线程
reject(command); // 如果不能再创建线程了,执行拒绝策略
}
结合上面execute的源码我们就知道了整个线程池执行的流程了,如下图所示:
最后我们再看看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 && // 线程池的状态为SHUTDOWN及以上,
! (rs == SHUTDOWN && // 线程池的状态为 SHUTDOEN
firstTask == null && // firstTask 为 null
! workQueue.isEmpty())) // 阻塞队列非空
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY || // 如果线程数的数量大于等于2^29 - 1 直接返回false,不能在创建新的线程了
wc >= (core ? corePoolSize : maximumPoolSize)) // 如果core为true与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
}
}
Worker w = new Worker(firstTask);
Thread t = w.thread;
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 c = ctl.get();
int rs = runStateOf(c);
if (t == null ||
(rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null))) {
decrementWorkerCount();
tryTerminate();
return false;
}
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
} finally {
mainLock.unlock();
}
t.start();
// It is possible (but unlikely) for a thread to have been
// added to workers, but not yet started, during transition to
// STOP, which could result in a rare missed interrupt,
// because Thread.interrupt is not guaranteed to have any effect
// on a non-yet-started Thread (see Thread#interrupt).
if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted())
t.interrupt();
return true;
}