并发包源码解读——ThreadPoolExecutor线程池
以一个简单的例子开始
//核心线程数,保持池内最少存活N个线程
int corePoolSize = 5;
//最大线程数,限制池内最多存活N个线程
int maximumPoolSize = 5;
//线程空闲时间,当池内线程空闲一段时间会自动销毁,但不会小于核心线程数
long keepAliveTime = 1000;
TimeUnit unit = TimeUnit.MILLISECONDS;
//阻塞队列,限制存放等待获取线程资源的最大任务数
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5);
ThreadFactory threadFactory = Thread::new;
//任务拒绝策略,当阻塞队列中任务堆满、无法入队后执行的逻辑
RejectedExecutionHandler handler = (r, executor) -> System.out.println("任务被拒绝了");
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
handler);
for (int i = 0;i<100;i++){
int finalI = i;
System.out.println("准备执行"+ finalI);
executor.execute(() -> {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("执行完成"+ finalI);
}
do {
if(!executor.isShutdown()){
executor.shutdown();
}
} while (!executor.isTerminated());
}
1、构造器
就是初始化各种参数
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
2、execute——执行
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//32-3=29
private static final int COUNT_BITS = Integer.SIZE - 3;
//低29位表示线程池内的线程个数,感觉跟ReentrantReadWriteLock的实现方式比较像
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//高3位表示线程状态
//111
private static final int RUNNING = -1 << COUNT_BITS;
//000
private static final int SHUTDOWN = 0 << COUNT_BITS;
//001
private static final int STOP = 1 << COUNT_BITS;
//010
private static final int TIDYING = 2 << COUNT_BITS;
//011
private static final int TERMINATED = 3 << COUNT_BITS;
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
public void execute(Runnable command) {
//执行的任务不能为空
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//取低29位线程数,如果执行任务时池内线程比核心线程数少,就加一个核心线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果线程池内线程数已经达到了核心线程数,或者线程增加失败了,就检查线程池运行状态,将任务放入队列
//增加线程失败的原因可能是池内线程数达到了核心线程数、线程没有放进HashSet中、或者线程没有启动成功等
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);
}
2.1、addWorker——向池内加线程
往线程池内加线程调用addWorker方法
//线程池是一个HashSet
private final HashSet<Worker> workers = new HashSet<Worker>();
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;
//cas让线程池内线程数加1,然后跳出外层循环
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) {
//增加线程池内线程通过ReetrantLock实现
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//取高3位运行状态
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();
}
//新建的线程成功放到线程池中了,就启动它
//注意Worker是实现Runnable接口的,启动后会调用run方法
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
//无论什么原因,只要线程启动失败
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
创建一个新线程Worker,构造器是这样的
Worker(Runnable firstTask) {
//这个时候偶线程还没运行,先设置-1
setState(-1); // inhibit interrupts until runWorker
//初始化这个线程要执行的任务
this.firstTask = firstTask;
//调用自己实现的ThreadFactory
this.thread = getThreadFactory().newThread(this);
}
线程启动失败后调用addWorkerFailed维护线程池
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//线程加到线程池了,但是启动失败,要移除
if (w != null)
workers.remove(w);
//然后把线程数量改回去
decrementWorkerCount();
//尝试停线程池
tryTerminate();
} finally {
mainLock.unlock();
}
}
final void tryTerminate() {
for (;;) {
int c = ctl.get();
//如果线程在运行,或者已经停止、或者已经关了在等着阻塞队列中的工作完成
//这几种状态都不能关,直接返回
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//如果线程池内还有线程,就尝试中断池内第一个线程
if (workerCountOf(c) != 0) { // Eligible to terminate
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));
//停止之后可以提前唤醒等待线程池停止的外部“主”线程
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
尝试中断线程调用interruptIdleWorkers,代码逻辑清晰就不赘述了
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();
}
}
2.2、remove——移除任务
移除任务的方法也比较简单,就是从队列中移除任务,然后尝试中断第一个线程
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
2.3、reject——执行拒绝策略
执行拒绝策略调用reject方法,是rejectedExecution的封装
其实就是执行我们实现了RejectedExecutionHandler的方法
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
2.4、runWorker——让线程执行任务
Worker实现了Runnable接口,它的run方法是ThreadPoolExecutor中runWorker方法的封装
public void run() {
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 ((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);
}
}
private Runnable getTask() {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
//检查运行状态,如果线程池已经停了,或者准备停但是正在等阻塞队列任务全部完成
//符合上述条件,维护线程数,然后返回上一个方法执行processWorkerExit回收线程
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
//超时的核心线程和超过核心线程数的线程会被回收
//allowCoreThreadTimeOut表示是否允许核心线程空闲超时被回收,可以在初始化ThreadPoolExecutor时设置
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//线程池内线程数大于核心线程数,或者从阻塞队列中取任务超时了
//如果线程池内有线程或者阻塞队列是空的,就维护线程数减1,同样准备执行processWorkerExit回收线程
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;
//没任务支持超时就在下一次for循环时回收
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
2.5、processWorkerExit——回收线程
getTask返回空时,当前线程要被回收
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//当前线程执行任务失败了,就先维护线程数-1
if (completedAbruptly)
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//ThreadPoolExecutor全局维护一个completedTaskCount,用来记录完成的任务个数
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;
}
//池内线程少于允许的最小线程,就增加线程
addWorker(null, false);
}
}
2.6、shutdown——停止线程池
调用shutdown停止线程池
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//首先调用checkShutdownAccess,这是跟SecurityManager有关的,一半SecuriityManager都为空不执行逻辑,不做介绍
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
自旋修改线程池状态为SHUTDOWN,当线程池状态不是运行或准备关机的状态时才会CAS修改状态
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
中断所有线程调用interruptIdleWorkers
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
3、总结
ThreadPoolExecutor底层用HashSet存线程,用BlockingQueue存任务
无论池内是否有空闲线程,任务到来时都会先进BlockingQueue
ThreadPoolExecutor是通过BlockingQueue的take方法实现任务监听的
池内核心线程是随着任务的到来而创建的,而并非线程池创建时就初始化核心线程。只要池内核心线程数不够,新来的任务都会创建新的线程来执行,然后被创建的线程会作为核心线程存在线程池中
线程池调用shutdown会先将线程池状态改成SHUTDOWN,等待所有任务执行完,然后再改成