线程池源码系列
一、接口层次
- Executor
- ExecutorService
- AbstractExecutorService
- ThreadPoolExecutor
- ForkJoinPool
- ScheduleExecutorService
- ScheduleThreadPoolExecutor
- Executors 线程池工具类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yzg9c7Nr-1633849989833)(.ThreadPoolExecutor.assets1624024421050.png)]
二、Executor
public interface Executor {
// 执行任务方法
void execute(Runnable command);
}
三、ExecutorSerivce
对父接口进行了功能扩展
- 控制线程池的操作
- 提交任务的操作
- 支持有返回值的任务
- 执行多个和任意任务的操作
public interface ExecutorService extends Executor {
// 关闭线程池
void shutdown();
// 立即关闭线程池
List<Runnable> shutdownNow();
// 线程池是否已关闭
boolean isShutdown();
// 线程池是否已销毁
boolean isTerminated();
// 等待线程池销毁 timout + unit
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
// 提交任务的方法 Callable 有返回值的任务
<T> Future<T> submit(Callable<T> task);
// 提交任务的方法 Runnable + result 也支持返回值
<T> Future<T> submit(Runnable task, T result);
// 提交 Runnable 无返回值
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
实现基本的方法
- 提供模板方法
- 具体的执行方法逻辑
1、创建任务 RunnableFuture 任务 -> FutureTask
// 接受 Runnable 任务 + T 的返回值类型
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
// 接受 Callable 任务(自带返回值)
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
2、提交任务
// 提交 Runnable 任务
public Future<?> submit(Runnable task) {
// 基本判空
if (task == null) throw new NullPointerException();
// 创建任务 FutureTask
RunnableFuture<Void> ftask = newTaskFor(task, null);
// 执行任务
execute(ftask);
// 返回 FutureTask
return ftask;
}
// 提交 Runnable + T 返回值的任务
public <T> Future<T> submit(Runnable task, T result) {
// 基本判空
if (task == null) throw new NullPointerException();
// 创建任务 FutureTask
RunnableFuture<T> ftask = newTaskFor(task, result);
// 执行任务
execute(ftask);
// 返回 FutureTask
return ftask;
}
// 提交 Callable 任务
public <T> Future<T> submit(Callable<T> task) {
// 基本判空
if (task == null) throw new NullPointerException();
// 创建任务 FutureTask
RunnableFuture<T> ftask = newTaskFor(task);
// 执行任务
execute(ftask);
// 返回 FutureTask
return ftask;
}
3、执行任务 - 执行全部任务
// 不带超时时间的执行所有任务 - 一定要执行完全部,除非出现异常
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
// 基本判空
if (tasks == null)
throw new NullPointerException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
// 标志位 - 是否全部完成
boolean done = false;
try {
// 循环创建任务,并将任务执行,获取到异步执行的任务 futures
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
// 循环等待所有任务执行完成
for (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
// 当前任务没有完成就调用 get 阻塞等待
if (!f.isDone()) {
try {
f.get();
// 这里如果我们的任务出现异常,那么会抛出,程序将中断 -> 跳转到 finally 块
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
// 所有任务正常执行完成设置标志位 true,表示全部执行完成
done = true;
// 返回我们的结果
return futures;
} finally {
// 如果没有被设置 true,表示任务没有完全被执行完,也即出现了异常情况
if (!done)
// 拿到任务,依次取消掉任务,当然已经完成的任务取消是没有效果的
// 详情见 FutureTask
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
4、执行任务 - 带超时时间执行全部任务
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
// 基本判空
if (tasks == null)
throw new NullPointerException();
// 时间转换为 纳秒 单位
long nanos = unit.toNanos(timeout);
// 异步执行的任务集合
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
// 一样的全部任务完成的标准位
boolean done = false;
try {
// 为了不影响计时出现偏差,这里先把所有的任务创建好
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
// 截至时间
final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
// 执行任务
for (int i = 0; i < size; i++) {
execute((Runnable)futures.get(i));
nanos = deadline - System.nanoTime();
// 检查是否超时,超时直接返回,这里返回的任务就有可能没有执行的任务
if (nanos <= 0L)
return futures;
}
// 循环等待任务执行完成
for (int i = 0; i < size; i++) {
Future<T> f = futures.get(i);
// 任务没有完成
if (!f.isDone()) {
// 再次超时检查,超时直接退出
if (nanos <= 0L)
return futures;
try {
// 超时阻塞等待
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
// 超时异常直接返回异步执行的任务 - 存在未完成的异步任务
return futures;
}
nanos = deadline - System.nanoTime();
}
}
// 全部执行完成,返回异步执行的任务 - 全部都已经执行完成的
done = true;
return futures;
} finally {
// 同理,没有全部执行完成-超时或出现了异常
if (!done)
// 依次取消任务 - 已完成的不会有影响
// 详情见 FutureTask
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
5、执行任务 - 执行任意一个任务
// 执行任意一个任务
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
// 带超时时间的执行任意一个任务
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
// 具体的执行方法
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
// 基本判空
if (tasks == null)
throw new NullPointerException();
// 任务大小
int ntasks = tasks.size();
// 任务数为0的情况,抛异常
if (ntasks == 0)
throw new IllegalArgumentException();
// 异步执行的任务集合
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
// ExecutorCompletionService -> 将当前线程池 this 传入其内部
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
try {
// 记录异常
ExecutionException ee = null;
// 超时时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
// 拿到任务迭代器
Iterator<? extends Callable<T>> it = tasks.iterator();
// next() 拿到第一个任务丢给 ExecutorCompletionService,内部对任务进行二次封装
futures.add(ecs.submit(it.next()));
// 任务数量 -1
--ntasks;
// 正在执行的任务数量 +1
int active = 1;
// 死循环
for (;;) {
// 任务执行完成时或任务取消时,会将任务丢到 ExecutorCompletionService 的队列中
// 如果任务没有完成,那么 poll()方法返回的就是 null
Future<T> f = ecs.poll();
// 这里表示任务没有完成
if (f == null) {
// 还有任务
if (ntasks > 0) {
// 任务数量 -1
--ntasks;
// 拿到下一个任务继续
futures.add(ecs.submit(it.next()));
// 正在执行的任务数量 +1
++active;
}
// 如果正在执行的任务为 0 了,表示执行完了,执行 break退出循环
else if (active == 0)
break;
// 如果是带超时的情况,检查是否超时
else if (timed) {
// 超时获取执行结果
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
// 没有拿到结果,表示超时了
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
}
// 如果其他情况都不满足 - take 方法获取会抛异常
else
f = ecs.take();
}
// 如果有执行完成的任务
if (f != null) {
// 正在执行的任务数量 -1
--active;
try {
// 拿到执行的结果返回
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
// 取消其他没有执行完成的任务,已完成的任务没有影响
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
五、ThreadPoolExecutor
0、Why
1. 传统方式
- 传统使用多线程方式
- 继承 Thread,重写 run 方法
- 实现 Runnable 重写 run 方法
- 实现 Callable 重写 call 方法
- 传统方式的弊端
- 线程是宝贵的系统资源,频繁创建,执行完就销毁,浪费系统资源
- 线程数量不可控,来一个任务就创建一个线程
- 不支持定时、定期任务执行
2. 线程池方式
- 线程池优点
- 管理线程,线程数量可控,线程重用,提升性能
- 支持任务挤压 - 阻塞队列存放任务
- 支持定时执行、周期执行任务
- 线程池要求
- 使用者需要对线程池运行原理有足够的了解
- 使用者需要了解不同线程池的应用场景及其正确使用方式
1、How to use
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor executor =
new ThreadPoolExecutor( 2,
5,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3));
// 提交 8 个任务
for (int i = 0; i < 8; i++) {
executor.submit(() -> {
System.out.println(Thread.currentThread().getName());
});
}
executor.shutdown();
executor.awaitTermination(100,TimeUnit.SECONDS);
}
2、线程池组件推理
- 线程容器 - 存放线程 HashSet workers
- 核心线程 - corePoolSize
- 临时线程 - (maximumPoolSize - corePoolSize)
- 临时线程存活时间 - long keepAliveTime
- 时间单位 - TimeUnit unit
- 任务队列 - 存放任务 - BlockingQueue workQueue
- 线程工厂 - 创建线程 - ThreadFactory threadFactory
- 拒绝策略 - 任务满了的解决方案 - RejectedExecutionHandler handler
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
3、线程池工作原理
- 第一次提交任务到线程池,创建核心线程处理任务,直到线程数量达到 corePoolSize 核心线程数
- 持续提交任务到线程池,此时将任务存放到任务队列 workQueue 中 ,直到任务队列满了
- 继续提交任务,此时将创建临时线程任务处理,直到线程数量达到 maximumPoolSize 最大线程数
- 此时任务队列满了、线程数达到最大值了如果继续提交任务,那么线程池将启用拒绝策略来拒绝任务,默认提供了四种拒绝策略
- 随着时间的推移,任务越来越少,那么线程池将根据设置的 keepAliveTime 、unit 进行销毁线程,直到销毁的线程数量达到 corePoolSize 为止
4、线程池工厂
public interface ThreadFactory {
// 创建线程
Thread newThread(Runnable r);
}
5、四大拒绝策略 - RejectedExecutionHandler
// ① 直接抛异常
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() {
}
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
// ② 调用者执行任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() {
}
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
// ③ 抛弃当前提交的任务
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() {
}
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
// ④ 抛弃最早提交的任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() {
}
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
// 任务队列队头任务弹出抛弃
e.getQueue().poll();
// 尝试执行新任务
e.execute(r);
}
}
}
6、阻塞队列 BlockingQueue - 多线程安全
// 增删改查
public interface BlockingQueue<E> extends Queue<E> {
boolean add(E e);
boolean offer(E e);
void put(E e) throws InterruptedException;
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
E take() throws InterruptedException;
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
int remainingCapacity();
boolean remove(Object o);
public boolean contains(Object o);
int drainTo(Collection<? super E> c);
int drainTo(Collection<? super E> c, int maxElements);
}
- ArrayBlockingQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- SynchronousQueue
7、FutureTask
public interface Future<V> {
// 取消任务
boolean cancel(boolean mayInterruptIfRunning);
// 是否已取消
boolean isCancelled();
// 是否完成
boolean isDone();
// 获取结果
V get() throws InterruptedException, ExecutionException;
// 超时获取结果
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
public class FutureTask<V> implements RunnableFuture<V> {
}
8、源码解读
1.源码分析
- 向ThreadPool提交任务 - execute()
- 创建新线程 - addWorker(Runnable firstTask, boolean core)
- 线程的主循环 - Worker.runWorker(Worker w)
- 从队列中获取排队的任务 - getTask()
- 线程结束 - processWorkExit(Worker w, boolean completedAbruptyly)
- shutdown()、shutdownNow()、tryTerminated()
计数通用逻辑:先+1,再处理,若处理失败再-1
2.变量
// ctl = 线程数量 + 线程池状态(高3位表示线程池状态,低29位表示线程池线程数量)
// 默认值 0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 29 位
private static final int COUNT_BITS = Integer.SIZE - 3;
// 向左移动29位,30位为1,其余为0,减1,则为 29个1
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 线程池运行状态
// ctl < 0 时代表运行状态
private static final int RUNNING = -1 << COUNT_BITS; // 111
private static final int SHUTDOWN = 0 << COUNT_BITS; // 000
private static final int STOP = 1 << COUNT_BITS; // 001
private static final int TIDYING = 2 << COUNT_BITS; // 010 过度状态
private static final int TERMINATED = 3 << COUNT_BITS; // 011
// 获取当前线程池运行状态 ~CAPACITY = 1110 0000 0000... :前面3个1,后面29个0
private static int runStateOf(int c) {
return c & ~CAPACITY; }
// 获取当前线程池的线程数量 CAPACITY = 0001 1111 1111... :前面3个0,后面29个1
private static int workerCountOf(int c) {
return c & CAPACITY; }
// 获取 ctl 的值
private static int ctlOf(int rs, int wc) {
return rs | wc; }
// 任务队列,存放任务
private final BlockingQueue<Runnable> workQueue;
// Worker -> Runnable workers 存放任务线程的集合
private final HashSet<Worker> workers = new HashSet<Worker>();
3.线程池状态
ThreadPool 线程池的5种状态:
- RUNNING :接收新任务和进程队列任务
- SHUTDOWN :不接收新任务,但是接收进程队列任务
- STOP :不接收新任务也不接收进程队列任务,并且中断正在执行中的任务
- TIDYING :所有任务终止,线程数量为0,线程池转为 TIDING,将会执行 terminated 钩子方法
- TERMINATED: terminated()执行完成
RUNNING: Accept new tasks and process queued tasks SHUTDOWN: Don't accept new tasks, but process queued tasks STOP: Don't accept new tasks, don't process queued tasks and interrupt in-progress tasks TIDYING: All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method TERMINATED: terminated() has completed
状态之间的转换:
- RUNNING -> SHUTDOWN:调用 shutdown() 方法
- (RUNNING/SHUTDOWN) -> STOP :调用shutdownNow()方法
- SHUTDOWN -> TIDING :队列和线程池都是空的
- STOP -> TIDING :线程池为空
- TIDING -> TERMINATED :钩子函数 terminated()执行完成
4.构造器
// 构造器开始
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;
}
5.execute(…)
public void execute(Runnable command) {
// 基本判空
if (command == null)
throw new NullPointerException();
// 获取 ctl 值:线程池状态及线程数
int c = ctl.get();
// ① 线程池线程数量小于核心线程数,添加核心线程
if (workerCountOf(c) < corePoolSize) {
// 提交任务,true表示核心线程,添加成功直接返回
if (addWorker(command, true))
return