类图
Executor -> ExecutorService -> AbstractExecutorService -> ThreadPoolExecutor
线程池的主要任务是将“任务”和“线程”解偶,生产者-消费者模式
线程池状态管理
高3位保存线程池的运行状态runState,低29位保存有效线程数量workerCount
@ReachabilitySensitive
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
相关计算
private static int runStateOf(int c) { return c & ~CAPACITY; } //计算当前运行状态
private static int workerCountOf(int c) { return c & CAPACITY; } //计算当前线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; } //通过状态和线程数生成ctl
线程池的运行状态
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS; //能接受新的任务,也能处理阻塞队列中的任务
private static final int SHUTDOWN = 0 << COUNT_BITS; // 不能接受新的任务,但能继续处理阻塞队列中的任务,中断空闲线程
private static final int STOP = 1 << COUNT_BITS; // 不能接受新的任务,也不处理阻塞队列中的任务,会中断所有线程
private static final int TIDYING = 2 << COUNT_BITS; // 所有的任务都被终止了,有效线程数为0
private static final int TERMINATED = 3 << COUNT_BITS; // 在terminated()方法执行完后进入该状态
创建线程池
newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newCachedThreadPool
有新任务就创建新的线程,线程空闲会被重复利用,线程空闲60s会被回收
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newScheduledThreadPool
执行延时或定时任务
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
关闭线程池
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
会立刻停止正在执行的任务
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;
}
awaitTermination
等待指定的时间让线程池关闭
任务管理
任务调度
execute方法完成
workerCount < corePoolSize
创建一个新的线程来执行新提交的任务
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
workCount >= corePoolSize && 阻塞队列未满
将新提交的任务添加到阻塞队列列表
if (isRunning(c) && workQueue.offer(command))
workCount >= corePoolSize && 阻塞队列已满 && workerCount < maximumPoolSize
创建并启动一个线程来执行新提交的任务
addWorker(command, false)
workerCount >= maximumuPoolSize
拒绝策略处理该任务
else if (!addWorker(command, false))
reject(command);
阻塞队列分类
线程池 | 阻塞队列 | 作用 |
---|---|---|
newFixedThreadPool | LinkedBlockingQueue | 一个由链表结构组成的有界队列,FIFO,默认容量为Integer.MAX_VALUE |
newCachedThreadPool | SynchronousQueue | 一个不存储元素的阻塞队列,每一个put操作,必须等待take操作,否则不能添加元素。支持公平锁和非公平锁。 |
newSingleThreadExecutor | LinkedBlockingQueue | |
newScheduledThreadPool | DelayedWorkQueue | 数组构成的优先级队列 |
任务申请
- 新创建的线程执行
- 空闲线程获取任务执行
主要由getTask方法实现 : runWorker -> getTask
- 线程池停止运行或shutdown且阻塞队列为空,返回null
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
- 线程数过多,返回null; 阻塞队列为空或获取不到任务返回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;
}
- 限时获取任务 || 阻塞获取任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
任务拒绝
当阻塞队列已满 && workerCount达到maximumPoolSize时,就要拒绝掉该任务。
拒绝策略是一个接口
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
四种拒绝策略
策略 | 描述 |
---|---|
AbortPolicy | 默认拒绝策略,丢弃任务并且抛出异常 |
DiscardPolicy | 丢弃任务,但不抛出异常 |
DiscardOldestPolicy | 丢弃队列最前面的任务,重新提交被拒绝的任务 |
CallerRunsPolicy | 由调用线程处理该任务 |
Worker线程管理
掌握线程的状态并维护线程的生命周期,继承AQS,实现独占锁,不可重入性反应线程的执行状态。
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread; //持有的线程
Runnable firstTask; // 第一个任务有可以为null
volatile long completedTasks; //已完成的任务计数
}
shutdown方法和tryTerminate方法重会去中断idle状态线程,判断线程是否处于idle状态通过Worker的tryLock方法(独占锁)
Worker线程增加
通过addWorker方法实现
线程池状态大于SHUTDOWN,则返回false
线程池状态 == SHUTDOWN && 新增加线程用于处理阻塞队列中的任务,继续下去
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && ! (rs == SHUTDOWN &&firstTask == null &&! workQueue.isEmpty()))
return false;
线程数量超过限制,返回false
线程数大于容量,核心线程数,最大线程数
int wc = workerCountOf(c);
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
return false;
最后增加线程,启动线程
Worker线程回收
核心线程无线等待获取任务,非核心线程限时获取任务,线程回收由processWorkerExit方法实现
final void runWorker(Worker w) {
......
try {
while (task != null || (task = getTask()) != null) {
.......
} finally {
processWorkerExit(w, completedAbruptly);
}
}
消除自身在线程池内的引用
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
如果用户状态异常导致线程退出,需要判断线程池状态,重新分配线程
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);
}
时序图:
参考:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html