Concurrent -- 01 -- ThreadPoolExecutor解析
相关文章:
在项目开发过程中,服务端会接收请求并进行处理,当请求数量不大时,我们可以为每个请求都分配一个线程,而当请求数量很大时,如果还是为每个请求都分配一个线程的话,会导致频繁地创建和销毁线程,从而大大降低了系统的效率,这个时候,线程池便派上了用场,通过对线程的重复使用,大大地提高了系统的效率
总的来说,线程池的优点可以归纳为以下几点
-
降低资源消耗
- 通过重复利用已创建的线程降低线程创建和销毁造成的消耗
-
提高响应速度
- 当任务达到时,可以不需要等待新的线程创建就能立即执行
-
提高线程的可管理性
- 线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控
在线程池中,ThreadPoolExecutor 类是最核心的一个类,想要透彻地了解线程池,则必须先了解这个类,在此之前,我们先来看下线程池的类图

一、Executor 接口
-
Executor 接口只有一个 execute(Runnable command) 方法,传入 Runnable 参数,用于执行任务
public interface Executor { void execute(Runnable command); }
二、ExecutorService 接口
-
ExecutorService 接口继承自 Executor 接口,并新增了 shutdown()、shutdownNow()、isShutdown()等一系列方法
public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException; <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
三、AbstractExecutorService 抽象类
- AbstractExecutorService 抽象类实现了 ExecutorService 接口,并提供了一些方法的默认实现,如:submit()、invokeAny()、invokeAll() 等方法
四、ThreadPoolExecutor 类
-
1、参数解析
-
首先我们来看下 ThreadPoolExecutor 类构造函数的源码
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; } -
由源码可知,ThreadPoolExecutor 类的构造函数共有七个参数,它们的具体作用分别如下
-
corePoolSize
-
核心线程数
-
线程池启动后默认是空的,只有当任务来临时才会创建线程进行处理
-
当核心线程空闲时,会一直等待新的任务,而不会被销毁回收
-
相关方法
-
prestartCoreThread()
-
预先创建一个核心线程,返回 true
-
此方法会覆盖在执行新任务时,创建核心线程的默认策略
-
如果此前所有的核心线程都已被创建,则调用该方法返回 false
-
-
prestartAllCoreThreads()
-
预先创建所有核心线程
-
此方法会覆盖在执行新任务时,创建核心线程的默认策略
-
-
-
-
maximumPoolSize
-
最大线程数
-
当 workQueue 使用无界队列 (如:没有设置 capacity 的 LinkedBlockingQueue) 时,此参数无效
-
-
keepAliveTime
-
非核心线程的最大存活时间
-
当非核心线程空闲时间超过最大存活时间时,则会被销毁回收
-
相关方法
-
allowCoreThreadTimeOut(boolean value)
- 设置是否允许核心线程超时
-
allowsCoreThreadTimeOut()
- 获取核心线程是否可以超时的标识
-
-
-
unit
-
keepAliveTime 参数的时间单位
-
一共有七种枚举常量,如下所示
常量名 含义 NANOSECONDS 纳秒,等于 $1 * 10^{-9}s$MICROSECONDS 微秒,等于 $1 * 10^{-6}s$MILLISECONDS 毫秒,等于 $1 * 10^{-3}s$SECONDS 秒 MINUTES 分 HOURS 时 DAYS 日
-
-
workQueue
-
工作队列
-
当线程池中线程数量达到核心线程数,且都处于活跃状态时,会将新提交的任务放入队列中,等待空闲的线程来获取处理
-
-
threadFactory
-
线程创建工厂
-
创建线程或线程池时尽量指定有意义的线程名称,方便出错时回溯
-
创建线程池的时候,尽量使用带有 ThreadFactory 的构造函数,并提供自定义的 ThreadFactory 实现或者使用第三方实现
-
-
handler
-
线程拒绝策略
-
一共有四种线程拒绝策略,如下所示
拒绝策略 含义 AbortPolicy 直接丢弃任务,抛出异常 (默认策略) CallerRunsPolicy 将任务分配给调用线程来执行 DiscardPolicy 直接丢弃任务,不抛出异常 DiscardOldestPolicy 丢弃队列中最早的任务,不抛出异常
-
-
-
-
2、线程池状态
-
线程池有五大状态,分别是:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED
-
RUNNING (-1)
- 接受新任务并处理排队任务
-
SHUTDOWN (0)
-
不接受新任务,但会处理排队任务
-
当线程处于 RUNNING 状态时,调用 shutdown() 方法会使线程池进入到该状态
-
-
STOP (1)
- 不接受新任务,也不处理排队任务,同时会中断正在处理的任务
-
TIDYING (2)
-
所有任务都已终止,workerCount (有效线程数) 为零
-
当线程池进入到该状态时,会调用 terminated() 方法
-
-
TERMINATED (3)
- terminated() 方法执行完毕后进入该状态
-
-
-
3、源码解析
-
线程池状态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // 29位 private static final int COUNT_BITS = Integer.SIZE - 3; // 线程池最大容量 private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits // 线程池运行状态 // 111 + 29个0 private static final int RUNNING = -1 << COUNT_BITS; // 000 + 29个0 private static final int SHUTDOWN = 0 << COUNT_BITS; // 001 + 29个0 private static final int STOP = 1 << COUNT_BITS; // 010 + 29个0 private static final int TIDYING = 2 << COUNT_BITS; // 011 + 29个0 private static final int TERMINATED = 3 << COUNT_BITS; // Packing and unpacking ctl // 获取线程池运行状态 private static int runStateOf(int c) { return c & ~CAPACITY; } // 获取线程池中线程数目 private static int workerCountOf(int c) { return c & CAPACITY; } // 反向构造 ctl 的值,初始值为 ctlOf(RUNNING, 0) private static int ctlOf(int rs, int wc) { return rs | wc; }-
ctl:
-
一个 32 位的 int 值,用于表示线程池的运行状态 (runState) 和线程池中的线程数目 (workerCount)
概念 含义 runState 占据 ctl 的高 3 位,表示线程池的运行状态 workerCount 占据 ctl 的低 29 位,表示线程池中的线程数目
-
-
COUNT_BITS
- 表示 29 位
-
CAPACITY
- 线程池最大容量 (
2^29 - 1)
- 线程池最大容量 (
-
runStateOf(int c)
private static int runStateOf(int c) { return c & ~CAPACITY; }-
获取线程池运行状态
-
c 代表 ctl 的值,将其与
~CAPACITY(111 00000 00000000 00000000 00000000) 进行 & 操作,c 的低 29 位与~CAPACITY的低 29 位00000 00000000 00000000 00000000进行 & 操作,无论 c 的低 29 位为何值,与00000 00000000 00000000 00000000进行 & 操作后都会变为00000 00000000 00000000 00000000,也就是舍弃了 c 的低 29 位;而 c 的高 3 位与~CAPACITY的高 3 位111进行 & 操作,c 的高 3 位还是会保持原值,这样我们就从 c 中解析出了 runState 的值
-
-
workerCountOf(int c)
private static int workerCountOf(int c) { return c & CAPACITY; }-
获取线程池中线程数目
-
c 代表 ctl 的值,将其与 CAPACITY 进行 & 操作,也就是与
000 11111 11111111 11111111 11111111进行 & 操作,c 的高 3 位与 CAPACITY 的高 3 位000进行 & 操作,无论 c 的高 3 位为何值,与000进行 & 操作后都会变为000,也就是舍弃了 c 的高 3 位值;而 c 的低 29 位与 CAPACITY 的低 29 位11111 11111111 11111111 11111111进行 & 操作,c 的低 29 位还是会保持原值,这样我们就从 c 中解析出了 workerCount 的值 -
线程池状态的常量可以通过值的大小来表示先后关系,如:
rs >= SHUTDOWN可用于表示线程的状态可能是 SHUTDOWN 或 STOP 或 TIDYING 或 TERMINATED,而不可能是 RUNNING
-
-
ctlOf(int rs, int wc)
private static int ctlOf(int rs, int wc) { return rs | wc; }-
反向构造 ctl 的值,初始值为
ctlOf(RUNNING, 0) -
rs 表示线程池的运行状态 (runState),其高 3 位有值,低 29 位全部为 0;wc 表示线程池中的线程数目 (workerCount),其高 3 为全部为 0,低 29 位有值
-
将 rs 与 wc 进行 | 操作,即用 rs 的高 3 位与 wc 的低 29 位填充成一个新的 int 值 (即 ctl 的值)
-
-
-
Worker
// 继承自 AbstractQueuedSynchronizer (AQS),实现了锁控制 private final class Worker extends AbstractQueuedSynchronizer implements Runnable { // Worker 类永远不会被序列化,但提供了一个 serialVersionUID 来避免编译警告 private static final long serialVersionUID = 6138294804551838833L; // Worker 运行所在的工作线程 (由线程工厂创建,如果创建失败,则为 null) final Thread thread; // 工作线程要执行的初始任务,可能为 null Runnable firstTask; // 工作线程完成的任务数量 volatile long completedTasks; // 使用给定的第一个任务和线程工厂创建的线程来构造 Worker Worker(Runnable firstTask) { // 限制线程直到 runWorker() 方法执行之前都不允许被打断 setState(-1); this.firstTask = firstTask; // 使用线程工厂创建线程 this.thread = getThreadFactory().newThread(this); } public void run() { // 调用外部的 runWorker() 方法 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) { // 设置当前拥有独占访问权限的线程 (null) 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) { } } } }-
线程池中每一个线程都被封装成了一个 Worker 对象,线程池维护的其实就是一组 Worker 对象
-
Worker 类继承自 AQS,并实现了 Runnable 接口,两个关键参数
thread和firstTask-
thread
- 工作线程,由线程工厂 (ThreadFactory) 创建,用于处理任务
-
firstTask
- 工作线程要执行的初始任务,即在构造方法中传入的任务
-
-
在 Worker 类的构造方法中,会通过
getThreadFactory().newThread(this)来新建一个线程,其中this表示的是当前对象,也就是 Worker 对象,由于 Worker 本身实现了 Runnable 接口,是一个线程,所以当一个 Worker 对象启动时,会调用自身的 run() 方法 -
Worker 类使用 AQS 来实现独占锁的功能
-
-
addWorker(Runnable firstTask, boolean core)
private boolean addWorker(Runnable firstTask, boolean core) { retry: for (;;) { int c = ctl.get(); // 获取线程池运行状态 int rs = runStateOf(c); /* * 如果线程池运行状态(rs) >= SHUTDOWN,则表示队列不再接收新的任务, * 满足该条件后,再判断后续的3个条件,只有有1个不满足就返回false, * 则if判断为true,返回false,方法执行结束,表示不需要添加新的工作线程 * 1、rs == SHUTDOWN * 线程池为SHUTDOWN状态,不再接受新任务,但会处理排队任务 * 2、firstTask == null * 工作线程执行的初始任务为null * 3、! workQueue.isEmpty() * 工作队列不为空 */ if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false; for (;;) { // 获取工作线程数 int wc = workerCountOf(c); /* * 如果工作线程数(wc) >= 线程池最大容量(CAPACITY),则返回false; * 这里的core为addWorker()方法的第二个参数 * 1、true,表示根据核心线程数(corePoolSize)来判断 * 2、false,表示根据最大线程数(maximumPoolSize)来判断 * 如果工作线程数(wc) >= 核心线程数(corePoolSize)/最大线程数(maximumPoolSize),则返回false */ if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; /* * 尝试增加线程池中线程数目(workerCount), * 如果成功,则跳出外层循环retry */ if (compareAndIncrementWorkerCount(c)) break retry; // 如果增加线程失败,则重新获取ctl的值 c = ctl.get(); /* * 重新获取线程池运行状态吗,并与先前获取的线程池运行状态(rs)相比较, * 如果不相等,则说明线程池状态已被改变,返回外层循环继续执行 */ 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 { // 根据firstTask构建Worker对象 w = new Worker(firstTask); // 获取Worker中的工作线程 final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // 获取线程池运行状态 int rs = runStateOf(ctl.get()); /* * 如果线程池运行状态(rs) < SHUTDOWN(即为RUNNING状态)或 * 如果线程池运行状态(rs)为SHUTDOWN状态且初始任务(firstTask)为null, * 则向线程池中添加线程(线程池状态为SHUTDOWN时,虽然不会再接受新任务, * 但仍然会处理排队任务) */ if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { // 检测工作线程是否处于活动状态 if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); // 如果工作线程不处于活动状态,则向workers(HashSet)中添加Worker workers.add(w); // 获取workers的大小 int s = workers.size(); /* * largestPoolSize * 用于记录线程池中出现过的最大线程数量 * 如果workers的大小(s) > largestPoolSize * 则将workers的大小(s)赋值给largestPoolSize */ if (s > largestPoolSize) largestPoolSize = s; // 将工作线程添加标识设为true workerAdded = true; } } finally { mainLock.unlock(); } /* * 如果工作线程已被添加, * 则启动工作线程,并将工作线程启动标识设为true */ if (workerAdded) { t.start(); workerStarted = true; } } } finally { // 如果工作线程未被启动,则回滚工作线程的创建 if (! workerStarted) addWorkerFailed(w); } return workerStarted; }-
addWorker() 方法主要用于在线程池中创建一个新的线程来执行任务,其有两个参数
firstTask和core-
firstTask
- 工作线程要执行的初始任务,即在构造方法中传入的任务
-
core
-
为 true 时,表示在新增线程时,会判断当前活动线程数是否小于核心线程数 (corePoolSize)
-
为 false 时,表示在新增线程时,会判断当前活动线程数是否小于最大线程数 (maximumPoolSize)
-
-
-
-
runWorker(Worker w)
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(); /* * 如果线程池状态 >= STOP(即为TIDYING、TERMINATED状态) * 且当前线程未被中断,则中断当前线程 * * 如果在执行if语句期间,执行了shutdownNow()方法,shutdownNow()方法 * 会将线程池中所有线程的状态设置为STOP,此时调用Thread.interrupted() * 来确保当前线程为非中断状态(interrupted()方法会清除当前线程的中断标识), * 且此时线程池状态 >= STOP(即为TIDYING、TERMINATED状态) * 且当前线程未被中断(已被interrupted()方法复位),则中断当前线程 */ 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; // 统计当前worker完成了多少任务 w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { /* * 线程结束时调用,做一些收尾工作 * 如:将worker从workers中移除、统计任务完成个数等 */ processWorkerExit(w, completedAbruptly); } }- runWorker() 方法主要用于执行任务
-
getTask()
private Runnable getTask() { // 标记上次从工作队列中获取任务是否超时 boolean timedOut = false; for (;;) { int c = ctl.get(); // 获取线程池运行状态 int rs = runStateOf(c); /* * 如果线程池状态(rs) >= SHUTDOWN(即为非RUNNING状态),再进行以下判断 * 1、线程池状态(rs)是否 >= STOP(即为STOP、TIDYING、TERMINATED状态) * 2、工作队列(workQueue)是否为空 */ if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { // 将线程池中线程数目-1,并返回null decrementWorkerCount(); return null; } // 获取线程池中线程数目 int wc = workerCountOf(c); /* * timed用于标记是否需要进行超时控制 * 1、allowCoreThreadTimeOut * 是否允许核心线程超时,默认为false * 2、线程池中线程数目(wc) > 核心线程数(corePoolSize) * 当线程池中线程数目大于核心线程数时, * 需要对非核心线程进行超时控制 */ boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; /* * 如果线程池中线程数目(wc) > 最大线程数(maximumPoolSize)或 * timed && timedOut(即当前操作需要进行超时控制且上次从工作队列中获取任务失败), * 满足上述条件之一后,再进行判断后续条件 * 如果线程池中线程数目(wc) > 1或工作队列(workQueue)为空,则满足条件 */ if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) { // 尝试将线程池中线程数目-1,并返回null,如果失败,则返回重试 if (compareAndDecrementWorkerCount(c)) return null; continue; } try { /* * 如果timed为true,则表示需要对工作队列(workQueue)的poll() * 方法进行超时控制,如果在keepAliveTime时间内没有获取到任务,则返回null; * 如果为false,则表示通过工作队列(workQueue)的take()方法来获取任务, * 若此时工作队列为空,则take()方法会进行阻塞,直到工作队列不为空,可获得任务为止 */ Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }- getTask() 方法主要用于从工作队列中获取任务
-
execute(Runnable command)
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); /* * 如果线程池中线程数目小于核心线程数(corePoolSize), * 则新建一个线程放入线程池中,用于执行任务 */ if (workerCountOf(c) < corePoolSize) { /* * 往线程池中添加线程,其中第二个参数用于限制 * 添加线程的数量是根据核心线程数(corePoolSize)来判断, * 还是根据最大线程数(maxPoolSize)来判断 * 1、true,表示根据核心线程数(corePoolSize)来判断 * 2、false,表示根据最大线程数(maxPoolSize)来判断 */ if (addWorker(command, true)) return; c = ctl.get(); } // 如果当前线程池是RUNNING状态,且往队列中添加任务成功 if (isRunning(c) && workQueue.offer(command)) { // 重新获取ctl的值 int recheck = ctl.get(); /* * 再次判断线程池的状态是否为RUNNING状态, * 如果不是,则移除之前添加进队列的任务, */ if (! isRunning(recheck) && remove(command)) // 使用线程拒绝策略对任务进行处理 reject(command); // 获取线程池中线程数量,并判断其是否等于0 else if (workerCountOf(recheck) == 0) // 往线程池中添加线程,但不执行 addWorker(null, false); } /* * 往线程池中添加线程,添加线程时根据最大线程数(maxPoolSize)来判断 * 如果添加失败,则使用线程拒绝策略对任务进行处理 */ else if (!addWorker(command, false)) reject(command); }-
execute() 方法主要用于提交任务,交由工作线程来进行处理
-
任务执行流程

-
当线程池接收到新任务时,先判断当前线程数量是否小于核心线程数 (corePoolSize),如果小于,则即使其他线程都处于空闲状态,也会创建新的线程 (核心线程) 来处理新任务
-
如果当前线程数量大于或等于核心线程数 (corePoolSize),则再判断工作队列 (workQueue) 是否有空位,如果有,则将新任务添加到工作队列 (workQueue) 中,等待空闲线程去获取处理
-
如果工作队列 (workQueue) 没有空位,则再判断当前线程数量是否小于最大线程数 (maximumPoolSize),如果小于,则会创建新的线程 (非核心线程) 来处理任务
-
如果当前线程数量大于或等于最大线程数 (maximumPoolSize),则使用线程拒绝策略来处理新任务
-
-
-

浙公网安备 33010602011771号