上一篇文章,聊了一下线程池的总体情况,今天主要聊聊线程池的核心类:ThreadPoolExecutor,接着上篇文章,先分析其重要的属性:
// 阻塞队列,用来存放提交的任务
private final BlockingQueue<Runnable> workQueue;
// 可重入锁
private final ReentrantLock mainLock = new ReentrantLock();
// worker集合,一个worker包装了一个线程
private final HashSet<Worker> workers = new HashSet<Worker>();
// 和锁绑定的条件
private final Condition termination = mainLock.newCondition();
// 用来记录曾经达到的最大线程数
private int largestPoolSize;
// 已完成的任务数量
private long completedTaskCount;
// 创建线程的工厂:非守护线程,且线程优先级为Thread.NORM_PRIORITY的线程
private volatile ThreadFactory threadFactory;
// 拒绝执行处理器
private volatile RejectedExecutionHandler handler;
// 线程保持存活的时间
private volatile long keepAliveTime;
// 是否允许回收核心线程,当其空闲时间达到keepAliveTime时
private volatile boolean allowCoreThreadTimeOut;
// 核心线程数的大小
private volatile int corePoolSize;
// 最大线程数的大小
private volatile int maximumPoolSize;
// 默认的拒绝执行策略
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
最为重要的几个参数,体现在其构造方法中,如下:
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;
}
- corePoolSize:核心线程数。当线程池的线程数量<corePoolSize,则创建线程,执行任务
- workQueue:阻塞队列。当线程池的线程数量>=corePoolSize,则会尝试将任务放入该队列。比较常见的是基于数组实现的ArrayBlockingQueue和基于链表实现的LinkedBlockingQueue
- maximumPoolSize:最大线程数。当线程池的线程数量>=corePoolSize,并且阻塞队列workQueue已满时,同时当线程池的线程数量<maximumPoolSize,则创建线程,执行任务
- handler:拒绝执行策略。当阻塞队列workQueue已满,并且线程池的线程数量>=maximumPoolSize时,则会执行拒绝策略。RejectedExecutionHandler 接口有4个实现类:AbortPolicy(抛出异常)、CallerRunsPolicy(调用者线程执行任务)、DiscardPolicy(直接丢弃任务)、DiscardOldestPolicy(丢弃等待最久的任务),默认是AbortPolicy,直接抛出异常。我们也可以实现RejectedExecutionHandler接口,自定义拒绝策略。
- threadFactory:线程工厂。它的默认实现是DefaultThreadFactory,只是负责创建非守护线程,线程优先级是Thread.NORM_PRIORITY的线程。
- keepAliveTime:存活时间。线程池中工作线程空闲时间达到keepAliveTime时,就会被销毁。
- unit:存活时间的单位。TimeUnit 里面的枚举值。
下面将从以下几个方面了解TheadPoolExecutor的运行机制:
- 线程池的创建
- 向线程池提交任务
- 线程池执行任务
- 关闭线程池
线程池的创建
ThreadPoolExecutor executorService = new ThreadPoolExecutor(10,30,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(10));
这里使用了参数最少的一个构造函数,创建了一个线程池,它会调用那个参数最多的构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
创建线程池、提交任务、关闭线程池,完整测试代码如下:
// 创建线程池
ThreadPoolExecutor executorService = new ThreadPoolExecutor(10,30,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(10));
// 提交50个任务
for (int i = 0; i < 50; i++) {
final int a = i;
Runnable task = () -> {
System.out.println(Thread.currentThread().getName()+"-->"+a);
};
executorService.execute(task);
}
// 关闭线程池
executorService.shutdown();
重点看看execute()方法:
public void execute(Runnable command) {
// 如果任务为null,则抛出空指针异常
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 线程池中的线程数量 < corePoolSize
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); // 否则,执行拒绝策略
}
从这里可以看到,其执行逻辑与线程池总体概述的执行流程基本一致。不难看出,其重点在于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);
// CAPACITY=2^29 - 1,如果大于核心线程数(最大线程数),就直接返回false
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已添加到线程池
Worker w = null;
try {
w = new Worker(firstTask); // 创建worker
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); // 将worker添加到集合中
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;
}
关闭线程池:shutdown()方法:
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查是否有权限关闭线程池
checkShutdownAccess();
// 设置线程池的状态为关闭状态
advanceRunState(SHUTDOWN);
// 中断空闲的线程
interruptIdleWorkers();
// 钩子函数
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}