线程的创建和销毁是昂贵的操作,会消耗大量的系统资源。线程池任务队列执行完成后会保留 corePoolSize 数量的线程,以备重复使用。这降低了线程创建和销毁的开销,提高了系统的性能和响应时间。
ThreadPoolExecutor
构造函数
线程池构造函数参数
- corePoolSize : 核心线程数量 ,线程池里面会一直保留,没有任务时休眠,有任务时唤醒
- maximumPoolSize : 最大线程数量 ,当核心线程数量不够完成任务,而外开启新线程进行工作,整个线程池的线程总数。
- keepAliveTime : 当新建线程超过了核心线程数,当没有任务时,非核心线程存活多久进行才销毁线程
- unit : keepAliveTime 的时间单位
- workQueue : 任务队列,当线程来不及处理任务时,存储在此队列里 这是一个阻塞队列的数据结构 关于阻塞队列 Java 队列介绍
- threadFactory : 线程工厂
- handler : 拒绝策略,当线程池线程数量已经到达最大值 maximumPoolSize ,且当 workQueue 任务队列无法添加任务时,如果继续再向线程池中添加任务时,决定线程池的操作策略。
线程工厂
线程池创建时线程时会调用 newThread() 方法 ,用于线程池创建线程时对线程进行统一配置 ,如给线程设置线程名,优先级等
java
public interface ThreadFactory {
Thread newThread(Runnable r);
}
拒绝策略
- CallerRunsPolicy : 如果线程池没有停止,就在当前添加任务到线程池的线程直接运行
- AbortPolicy : 抛出 RejectedExecutionException 异常,线程池默认策略
- DiscardPolicy : 直接废弃任务,当什么都没发生
- DiscardOldestPolicy : 如果线程池没有停止,把任务队列里面一个老的任务删除,新任务添加上去
java
public interface RejectedExecutionHandler {
// r 为添加的 Runnable, executor 如当前线程池
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
线程池的状态
线程池使用一个 int 类型参数的前 3 位表示线程池的状态,后 29 位表示线程池的线程数量。并且通过原子类 AtomicInteger 包装,ctl 初始化为 RUNNING 状态,线程数量为 0.
通过打印成二机制,理解起来会更清楚。
arduino
/* 计算后的数值 二进制表示
COUNT_MASK : 00011111111111111111111111111111
RUNNING : 11100000000000000000000000000000
SHUTDOWN : 00000000000000000000000000000000
STOP : 00100000000000000000000000000000
TIDYING : 01000000000000000000000000000000
TERMINATED : 01100000000000000000000000000000
*/
线程池状态只看前 3位,
- 只有 RUNNING 为负数,
- SHUTDOWN 为 0.
- STOP,TIDYING,TERMINATED 是正数的最高位 所以可以通过数值计算进行状态比较。
如 小于 SHUTDOWN 的只有 RUNNING ,通过这个能够判断线程池正在运行。
java
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
// 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;
private static final int TERMINATED = 3 << COUNT_BITS;
// 获取线程数量,只取后面 29位即可
private static int workerCountOf(int c) { return c & COUNT_MASK; }
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;
}
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;
}
- RUNNING: 接收新的任务,并且处理入队的任务
- SHUTDOWN: 不接收新的任务但是处理已经入队的任务
- STOP: 不接收新的任务,也不处理入队的任务,中断正在处理任务的线程
- TIDYING: 当所有的任务已被停止 ,线程数量为 0。线程池的状态为 TIDYING 然后会执行 terminated() 方法 ,terminated() 方法执行完成,状态会转移到 TERMINATED
- TERMINATED: 线程池完全停止状态
---
title: 线程池状态时序图
---
sequenceDiagram
RUNNING->>SHUTDOWN: shutdown()
RUNNING->>STOP: shutdownNow()
SHUTDOWN->>TIDYING: 当线程池中所有线程已被终止并且任务队列为空
STOP->>TIDYING: 当线程池中所有线程已被终止并且任务队列为空
TIDYING->>TERMINATED: 当 terminated() 执行完成
把任务添加到线程池进行执行
java
public void execute(Runnable command) {
// 任务为空直接抛异常
if (command == null)
throw new NullPointerException();
// 获取线程池当前状态
int c = ctl.get();
// 如果线程个数小于核心线程数量,直接调用 addWorker 开启新核心线程
if (workerCountOf(c) < corePoolSize) {
// 开启新线程成功直接返回 ,注意 addWorker 参数 command 不为 null ,第二个参数为 true 表示核心线程
if (addWorker(command, true))
return;
c = ctl.get();
}
// 线程池处于 RUNNING 状态 ,并且任务队列添加任务成功
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get(); // 再次获取线程池状态
// 线程池不是 RUNNING 状态,并且移除成功 remove 的时候会尝试终止线程池
if (! isRunning(recheck) && remove(command))
reject(command); // 拒绝执行任务
// 线程池正在运行中,核心线程设置为 0 ,command 已加入到任务队列
// 当线程池运行线程数量为 0 时 , 需要开启一个线程进行处理刚添加到任务队列的 command
else if (workerCountOf(recheck) == 0)
addWorker(null, false); // 开启一个没有初始运行任务的非核心线程
}
else if (!addWorker(command, false)) // 无法添加,可能意味着任务队列达到上限,开启非核心线程
reject(command); // 非核心线程无法创建时,拒绝执行任务
}
创建线程
java
/*
修改ctl失败时 需要重新加在 ctl的值 。有两层无限循环进行检查
第一层无限循环 有 retry 标记,检查了线程池的状态,是否停止
第二层无限循环 检查的是线程池数量是否超过了设定值
*/
// firstTask 代表新建线程的第一个任务,core 代表是否核心线程
private boolean addWorker(Runnable firstTask, boolean core) {
// retry 标记,用于跳出多重循环
// break continue 加 retry 代表操作的是 retry: 紧接着的for循环
retry:
for (int c = ctl.get();;) {
// 大于等于 SHUTDOWN ,只能是 SHUTDOWN STOP,TIDYING,TERMINATED 这几种
// 当线程池状态是 SHUTDOWN 时 ,firstTask 为 null,并且任务队列不为空,可能才会开启线程进行完成任务队列中已添加的任务
// 当线程池状态是 STOP,TIDYING,TERMINATED 时直接返回 false ,不会开启新线程。
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
// 请注意:我们初始化线程参数的时候并没有校验 corePoolSize,maximumPoolSize 数值最大值范围,可能超过29位,
// 所以必须 与上 COUNT_MASK 去除前3位
// 判断线程数量是否超过核心线程数或者最大线程数,超过了直接返回 false
// 没有超过的话,进行新开线程。
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
// 线程数量加 1成功 ,跳出 retry 循环
if (compareAndIncrementWorkerCount(c))
break retry;
// 原子类加 1 失败,说明其他线程已更改 ctl 值 重新获取
c = ctl.get(); // Re-read ctl
//当线程池状态大于等于 SHUTDOWN compareAndIncrementWorkerCount CAS失败
// 是 由于线程池状态发生了变化,直接跳到第一层循环
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// 否则 compareAndIncrementWorkerCount CAS失败 由于线程数量发生了变化,重试第二层循环
}
}
// 通过了线程池的状态和数量检查,进行开启线程
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建 Worker 对象,构造函数里面会调用 ThreadFactory.newThread()方法创建线程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
// 如何线程不是刚创建的线程,抛出异常
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
workers.add(w); // 把 w 添加到集合中
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize) // 记录线程池中开的最大线程数
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
// 如果 worker添加了,进行启动线程
if (workerAdded) {
t.start(); // 启动线程会执行,Worker 的 run 方法
workerStarted = true;
}
}
} finally {
// 如果未启动,调用 addWorkerFailed 方法
if (! workerStarted)
addWorkerFailed(w);
}
// 返回启动状态
return workerStarted;
}
// 如果创建线程失败
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w); // 移除启动失败的线程
decrementWorkerCount(); // 线程池数量 -1
tryTerminate(); // 尝试终止线程池
} finally {
mainLock.unlock();
}
}
执行线程
Worker 继承 了 AbstractQueuedSynchronizer
java
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
final Thread thread;
Runnable firstTask;
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
// 当启动线程时会调用此方法
public void run() {
runWorker(this);
}
// 0 代表未被锁定状态
// 1 代表被锁定状态
protected boolean isHeldExclusively() {
return getState() != 0;
}
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(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true; // 线程是否异常退出
try {
// task 为 firstTask ,通过 getTask()去任务队列中拿 task ,
// 如果 task 为空会退出 while 循环 ,线程会终止 。
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); // 任务执行之前
try {
task.run(); // 开始执行任务
afterExecute(task, null); // 任务执行之后
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
}
} finally {
task = null; // task 设置为 null
w.completedTasks++; // 记录线程完成的 completedTasks
w.unlock();
}
}
completedAbruptly = false; // 非异常退出
} finally {
// 处理线程退出
processWorkerExit(w, completedAbruptly);
}
}
// 最大线程数,核心线程数,是否允许核心线程超时 都是可以动态设置的
// 获取任务,当返回的task 为 null,就可以正常退出线程
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
// 大于等于 SHUTDOWN ,只能是 SHUTDOWN STOP,TIDYING,TERMINATED 这几种
// 当线程池状态是 SHUTDOWN 时 ,并且任务队列为空 返回 null
// 当线程池状态是 STOP,TIDYING,TERMINATED 时直接返回 null
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
decrementWorkerCount(); // 返回 null 之前 ,线程数 -1
return null; // 返回 null 代表线程是 正常退出的
}
int wc = workerCountOf(c); // 获取线程数
// 允许核心线程超时,或者当前线程数大于核心线程数
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 1.当前线程数大于最大线程数
// 2.当前线程数大于核心线程数,并且任务队列为空
// 3.核心线程运行超时,当前已经超时 ,并且任务队列为空
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c)) // 线程数 -1 ,返回 null
return null;
continue;
}
try {
Runnable r = timed ? // 如果允许核心线程超时,任务队列没有任务会等待 keepAliveTime 时间
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take(); // 如果任务队列没有任务会一直阻塞等待
if (r != null) // 如果拿到的 任务 ,返回 r
return r;
timedOut = true; // 如果 r 为 null ,说明超时
} catch (InterruptedException retry) {
timedOut = false; // 或者 等待任务队列时,被 interrupt() ,没有超时
}
}
}
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // 异常退出 ,统计线程数 -1,正常退出 ,已经减过 1
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks; // 统计已完成的任务数
workers.remove(w); // 去除 Worker
} finally {
mainLock.unlock();
}
// 尝试终止线程池
tryTerminate();
int c = ctl.get();
// 线程池状态为 RUNNING,SHUTDOWN
if (runStateLessThan(c, STOP)) {
// 正常退出
if (!completedAbruptly) {
// 运行核心线程超时 min 为 0 ,否则为 corePoolSize
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 当 min 为 0 ,任务队列不为空
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 如果当前线程池还是其他线程存活 直接返回
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 当前线程池状态为 SHUTDOWN ,线程池没有其他线程 ,并且任务队列不为空
// 开启一个线程来执行剩下未完成的任务
addWorker(null, false);
}
}
// 尝试终止线程池
final void tryTerminate() {
for (;;) {
int c = ctl.get();
// 当以下几种情况下 直接返回,不更改线程池状态
// 1. 线程池状态为 RUNNING
// 2. 线程池状态为 TIDYING ,TERMINATED
// 3. 线程池状态为 SHUTDOWN 并且任务队列不为空
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
return;
// 线程数不为 0 时 中止空闲的线程 直接返回,不更改线程池状态
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(); // 执行 terminated() 方法
} finally {
ctl.set(ctlOf(TERMINATED, 0));// 当前线程池状态设置为 TERMINATED
termination.signalAll(); // 通知等待线程池终止的线程线程已终止
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
停止线程池
java
// 停止线程池,但是有不会清除任务队列,等待任务队列执行完成
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN); // 把线程池状态置为 SHUTDOWN
interruptIdleWorkers(); // 中止空闲的线程
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate(); // 尝试停止线程池
}
// 立即停止线程池,未完成的任务列表会被清除并返回
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP); // 把线程池状态置为 STOP
interruptWorkers(); // 中止所有的线程
tasks = drainQueue(); // 移除未完成的任务队列
} finally {
mainLock.unlock();
}
tryTerminate(); // 尝试停止线程池
return tasks;
}
// 设置线程池的状态
private void advanceRunState(int targetState) {
// assert targetState == SHUTDOWN || targetState == STOP;
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
// 没有调用过 interrupt(),并且能够获取锁 ,说明在getTask()方法中等待获取任务队列的任务
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt(); // 调用 interrupt() 会抛出 InterruptedException
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
private void interruptWorkers() {
// assert mainLock.isHeldByCurrentThread();
for (Worker w : workers)
w.interruptIfStarted(); // 只要线程启动了 调用 interrupt()
}
Executors
Executors 工具类提供了几个静态方法快速创建各种类型的线程池。
- newCachedThreadPool()
- 创建一个 0 核心线程数 ,最大线程数为 Integer.MAX_VALUE ,没有任务时线程保持存活 60 秒。
SynchronousQueue<Runnable>()
是一个零容量的队列,不会保存元素用于后续的访问,当一个线程试图向中插入元素时,它会被阻塞,直到另一个线程从队列中取走这个元素,同样地,当一个线程试图从 中取走元素时,它也会被阻塞,直到另一个线程将元素放入队列中 。当有大量任务耗时任务添加到此线程池时,会创建大量线程,不会限制创建线程的数量,会消耗很多系统资源,甚至OOM 需要特别注意
- 创建一个 0 核心线程数 ,最大线程数为 Integer.MAX_VALUE ,没有任务时线程保持存活 60 秒。
- newSingleThreadScheduledExecutor()
- 创建单核心线程数为 1 ,最大线程数也为 1 ,阻塞队列
LinkedBlockingQueue<Runnable>()
可以保存 Integer.MAX_VALUE 任务 ,当有大量任务耗时任务添加到此线程池时,需要注意任务队列 OOM
- 创建单核心线程数为 1 ,最大线程数也为 1 ,阻塞队列
- newFixedThreadPool(int nThreads)
- 创建固定线程数量的线程池 ,单核心线程数为 nThreads ,最大线程数也为 nThreads ,阻塞队列 也是
LinkedBlockingQueue<Runnable>()
需要注意任务队列 OOM
- 创建固定线程数量的线程池 ,单核心线程数为 nThreads ,最大线程数也为 nThreads ,阻塞队列 也是
- newScheduledThreadPool()
- 创建 ScheduledExecutorService ,可设置定时任务,周期任务的线程池 。阻塞队列
DelayedWorkQueue()
也是可以保存Integer.MAX_VALUE 任务 ,当有大量任务耗时任务添加到此线程池时,需要注意任务队列 OOM
- 创建 ScheduledExecutorService ,可设置定时任务,周期任务的线程池 。阻塞队列