线程池简介
线程池主要解决两个问题:(1)当执行大量异步任务时线程池能够提供较好的性能,线程池中的线程是可以复用的,不需要每次执行异步任务时都重新创建和销毁线程;(2)线程池提供了一种资源限制和管理的手段
线程池数据结构
线程池配置
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;
}
(1) corePoolSize: 核心线程数,在线程池中始终维护的线程个数
(2) maximumPoolSize: 线程池最大线程数
(3) keepAliveTime: 存活时间,当线程池中的线程数量比核心线程数量多,并且是闲置状态,则这些闲置的线程能够存活的最大时间
(4) unit: 存活时间的单位
(5) workQueue: 用于保存等待执行的任务的阻塞队列
(6) threadFactory: 创建线程的工厂
(7) handler: 拒绝策略,当队列满且线程个数达到maximumPoolSize后采取的策略
线程池状态
JDK将线程数量(workerCount)和线程池状态(runState)两个变量存储在ctl这一个字段中,其中最高三位存储线程池状态,其余29位存储线程个数。
// 初始,线程池状态位RUNNING,线程数位0
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;
// 线程池的5种状态
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;
private static final int TERMINATED = 3 << COUNT_BITS;
// 从ctl中分别得到runState和workCount
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
// 将runState和workCount合并到Ctrl中
private static int ctlOf(int rs, int wc) { return rs | wc; }
线程池的状态只会从小的状态值往大的状态值迁移,不会逆向迁移,线程池的5个状态迁移过程如下:
线程池运行任务
任务提交
execute()方法的作用是提交任务到线程池中执行,执行过程如下:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 1. 当前线程池中线程个数小于corePoolSize则开启新线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 2 .如果线程池处于Running状态,且能添加任务到阻塞队列
if (isRunning(c) && workQueue.offer(command)) {
// 2.1 二次检查
int recheck = ctl.get();
// 2.2 如果当前线程池不是Running状态,删除任务并执行拒绝策略
if (! isRunning(recheck) && remove(command))
reject(command);
// 2.3 如果当前线程池为空,则增加一个线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 3. 如果队列满,则新增线程,新增失败则执行拒绝策略
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);
// 1. 返回false的三种情况
//(1)当前线程池为STOP,TIDYING,TERNIBTED
//(2)当前线程池为SHUTDOWN,当前任务非NULL
//(3)当前线程池为SHUTDOWN,且任务队列为空
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
return false;
// 2. 循环CAS增加线程个数
for (;;) {
int wc = workerCountOf(c);
// 2.1 线程个数超过限制返回false
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 2.2 CAS增加线程个数
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get();
if (runStateOf(c) != rs)
continue retry;
}
}
// 3. 到这里就是创建线程池线程成功
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 3.1 创建Worker
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 3.2 加独占锁,实现worker的同步
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
// 3.3 重新检查线程池状态
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
// 3.4 添加任务
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 3.5 添加任务成功后,启动线程池线程
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
任务执行
Work类是线程池中的线程包装类,它实现了Runnable接口并实现了run()方法,Work类也实现了AQS,使用线程内部锁实现任务执行和线程中断的同步。
// 线程池中线程
final Thread thread;
// 初始化Work时的第一个任务
Runnable firstTask;
// 该线程完成的数目
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // 在调用runWork前禁止中断
this.firstTask = firstTask; // 第一个任务
this.thread = getThreadFactory().newThread(this); // 创建一个线程
}
// 线程执行
// 在addWork()方法中调用t.start()执行该方法,使用work的内部thread执行work内部的run()方法
public void run() {
runWorker(this);
}
在构造方法内线设置Worker的状态为-1,这是为了避免当前Worker在调用runWorker()方法前被中断(当其他线程调用线程池的shutdown时,如果Worker状态>=0则会中断线程),这里设置为-1,所以线程不会被中断。在runWork()中,会先执行unlock()方法,该方法则是将state设置为0,所以这时调用shutdownNow会中断线程。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
// 1. 将state设置为0,允许中断
w.unlock();
boolean completedAbruptly = true;
try {
// 2. 若task==null且getTask() == null时,退出循环,即结束线程
while (task != null || (task = getTask()) != null) {
// 3. 获取工作线程内部持有的独占锁,保证任务执行期间,线程不被中断
w.lock();
// 4. 如果线程池被shutdownNow,则会直接中断当前线程
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 5. 执行用户提交的任务
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 {
// 6. 完成的任务置null,增加线程完成的任务数量,并解锁
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 7. 线程退出后,回收线程
processWorkerExit(w, completedAbruptly);
}
}
在任务执行期间加锁,是为了避免在任务执行期间,其他线程调用了shutdown后正在执行的任务被中断(shutdown只会中断当前被阻塞挂起的线程)
获取任务
Work对象初始化时绑定一个任务,待绑定的任务执行完后,
private Runnable getTask() {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 1. 判断线程池状态,确认是否需要退出
//(1)当线程池状态>=STOP时,返回null,减少线程数
//(2)当线程池处于SHUTDOWN,且任务队列为空,返回null,减少线程数
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 2. 断是否允许超时
//(1)非核心线程数默认允许超时
//(2)核心线程数是否允许超时由allowCoreThreadTimeOut参数决定
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 3. 当线程数大于1,或者工作队列为空时,下面两种情况会返回null
//(1)当线程数大于最大线程数时,返回null,减少线程数
//(2)当允许超时且超时时,返回null,减少线程数
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 4. 在任务队列中获取任务,允许超时时,要超时阻塞等待线程,且可以被中断,
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
// 5. 当线程shutdown或者shutdownNow时,会中断等待的线程
// 中断的线程再次进入for循环,再判断线程池状态时可以选择退出执行或继续执行
timedOut = false;
}
}
}
线程退出
线程获取不到任务时,会执行退出逻辑,在退出逻辑中都会尝试关闭线程池,并且如果线程关闭后的数量低于预期(核心数或者当任务队列不为空,至少保留一个线程),会再重新创建线程。
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly)
decrementWorkerCount();
// 1. 统计整个线程池完成的任务个数,并从线程池中删除该线程包装类Work
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 2. 尝试设置线程池状态为TERMINNATED,下面的情况会将线程池社会中为TERMINNATED
// (1)当前是SHUDOWN状态,且工作队列为空
// (2)当前是STOP状态,当前线程池中没有活动线程
tryTerminate();
// 3. 如果当前线程池个数小于核心线程数,则增加
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
// 3.1 如果核心线程池允许回收,则最小线程数位0,否则最小线程数位corePoolSize
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 3.2 任务不为空,要保留一个线程
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return;
}
// 3.3 线程数小于min时,再创建线程
addWorker(null, false);
}
}