线程池源码

线程池源码系列

一、接口层次

  • 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;
        // 再次获取ctl,以防另外的线程对线程池进行状态修改
        c = ctl.get();
    }
    // ② 添加任务失败了,核心线程数满了,检查线程池处于运行状态,往队列添加任务
    if (isRunning(c) && workQueue.offer(command)) {
        // 任务队列添加任务成功,再次获取 ctl 
        int recheck = ctl.get();
        // 检查是否还在运行状态,如果没有在运行了,remove 掉当前添加进去的任务
        if (! isRunning(recheck) && remove(command))
            // 并拒绝接收当前任务
            reject(command);
        // 线程池线程数量为 0 了
        else if (workerCountOf(recheck) == 0)
            // 添加非核心线程来执行任务 false表示非核心线程,null表示补充线程
            addWorker(null, false);
    }
    // ③ 队列满了,添加非核心线程执行任务
    else if (!addWorker(command, false))
        // ④ 如果添加失败,拒绝当前任务
        reject(command);
}
6.addWorker(…)
// 创建线程并执行任务,core为 true表示创建核心线程,false表示创建临时线程
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        // 获取 ctl 值
        int c = ctl.get();
        // 线程池运行状态
        int rs = runStateOf(c);
        // rs >= SHUTDOWN = SHUTDOWN/STOP/TIDING/TERMINATED 
        // rs == SHUTDOWN 不可以接收外部任务
        // first == null 外部提交任务为空
        // ! workQueue.isEmpty() 任务队列不为空
        // ① 一言以蔽之:线程池处于关闭状态,还有任务提交进来,直接返回 false 表示添加失败
        // firstTask == null 表示是添加补充线程来执行队列中的任务addWorker(null, false);
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
        // 这个循环就是添加线程数+1
        for (;;) {
            // 获取线程池线程数量
            int wc = workerCountOf(c);
            // ② 线程数大于最大容量 
            if (wc >= CAPACITY ||
                // ③ 创建核心线程时线程数超过了corepoolSize,创建非核心线程数超过了最大线程数时
                wc >= (core ? corePoolSize : maximumPoolSize))
                // 直接返回 false 表示失败
                return false;
            // ④ CAS线程数+1,成功直接跳过大循环往后执行
            if (compareAndIncrementWorkerCount(c))
                // 跳过大循环,跳到双层循环下面的代码执行
                break retry; 
            // ⑤ CAS添加线程数失败了
            // 再次获取 ctl 值
            c = ctl.get();
            // 查看当前线程池运行状态和前面的状态是否一致,不一致则重新从外层循环开始
            if (runStateOf(c) != rs)
                // 退出当前循环,跳到外层循环继续下一次循环
                continue retry; 
            // 一致则继续在内部循环运行
        }
    }
    // 到这里表示上面已经添加线程数成功了
    boolean workerStarted = false; // 任务已启动标志位
    boolean workerAdded = false; // 任务已添加标志位
    Worker w = null;
    try {
        // ① 包装任务,并创建线程 - 设置 AQS state = -1,禁止中断,直到 runWorker
        w = new Worker(firstTask);
        // 拿到线程
        final Thread t = w.thread;
        if (t != null) {
            // 可重入锁,加锁
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // 拿到线程池运行状态
                int rs = runStateOf(ctl.get());
                // rs < SHUTDOWN = RUNNING 线程池运行中
                if (rs < SHUTDOWN ||
                    // 补充线程
                    (rs == SHUTDOWN && firstTask == null)) {
                    // 线程已启动了,抛异常
                    if (t.isAlive()) 
                        throw new IllegalThreadStateException();
                    // ② 添加包装后的任务到 HashSet集合中
                    workers.add(w);
                    // 获取集合大小,并将此时的值赋值给 largestPoolSize
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    // 修改已添加标志位
                    workerAdded = true;
                }
            } finally {
                // 解锁
                mainLock.unlock();
            }
            // ③ 任务添加成功,启动线程
            if (workerAdded) {
                t.start();
                // 修改已启动标志位
                workerStarted = true;
            }
        }
    } finally {
        // ④ 没有启动成功
        if (! workerStarted)
            // 移除任务,并将线程数-1
            addWorkerFailed(w);
    }
    // 返回是否启动成功结果
    return workerStarted;
}
7.runWorker(…)
final void runWorker(Worker w) {
    // 当前worker线程
    Thread wt = Thread.currentThread();
    // 当前worker线程的任务
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // addWorker时设置 -1禁止中断,到这里允许中断 - 设置 AQS state = 0
    boolean completedAbruptly = true;
    try {
        // task != null 表示是第一个任务
        // task == null 执行task = getTask() 从任务队列拿任务
        // ① 一言以蔽之:任务不为 null 的情况
        while (task != null || (task = getTask()) != null) {
            // 设置状态位 - 表示此线程为非空闲线程
            w.lock();
            // ② runStateAtLeast(ctl.get(), STOP) => rs >= STOP 线程池处于关闭状态
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 // 清空线程中断标志位 
                 (Thread.interrupted() &&
                  // 再次判断 rs >= STOP 线程池处于关闭状态
                  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 {
                // FOR GC
                task = null;
                // 完成任务数+1
                w.completedTasks++;
                // 任务执行完成,设置线程标志位 - 表示当前线程空闲
                w.unlock();
            }
        }
        // getTask() 内部catch了异常,因此只有2个钩子的方法会导致 completedAbruptly=true
        // beforeExecute/afterExecute 会导致 completedAbruptly = true,用户导致的异常
        completedAbruptly = false;
    } finally {
        // 根据 completedAbruptly 处理情况不同的逻辑
        processWorkerExit(w, completedAbruptly);
    }
}
8.getTask()
private Runnable getTask() {
    // 超时标志位
    boolean timedOut = false;
    // 死循环
    for (;;) {
        // 拿到当前 ctl
        int c = ctl.get();
        // 线程池运行状态
        int rs = runStateOf(c);
        // 线程池处于SHUTDOWN状态,不接收外部任务
        // 且线程池处于STOP状态,不接受外部任务和队列任务,或者任务队列为空
        // ① 一言以蔽之:没有任务了
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            // 线程数-1
            decrementWorkerCount();
            return null;
        }
        // 拿到线程数
        int wc = workerCountOf(c);
        // 允许核心线程超时销毁或者线程数大于核心线程数
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        // 线程数大于最大线程数且超时了
        if ((wc > maximumPoolSize || (timed && timedOut))
            // 线程数大于1,或任务队列空了
            && (wc > 1 || workQueue.isEmpty())) {
            // CAS线程数-1
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        try {
            // timed 一般是 false 线程数大于了核心线程,带时间poll等待任务
            // 否则阻塞等待任务 take()
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
            workQueue.take();
            // 拿到任务就返回
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}
9.processWorkerExit(…)
// 线程池线程退出情况处理 - 用户导致异常导致线程池线程退出,需要给线程池补充线程
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // ① 用户导致了异常,线程池线程数-1
    if (completedAbruptly)
        decrementWorkerCount();
    // 加锁操作
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        completedTaskCount += w.completedTasks;
        // ② 从 workers 集合中移除当前的 worker
        workers.remove(w);
    } finally {
        // 解锁操作
        mainLock.unlock();
    }
    // 尝试销毁
    tryTerminate();
    // 获取线程池状态
    int c = ctl.get();
    // runStateLessThan(c, STOP) = RUNNING/SHUTDOWN
    if (runStateLessThan(c, STOP)) {
        // ③ 是否用户导致了异常,如果是,跳到addWorker(null, false);补充一个worker线程
        // 也即:用户导致了异常,线程池会新创建一个线程
        if (!completedAbruptly) {
            // 获取核心线程数大小
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            // 核心线程数如果设置为 0 且任务队列还有任务,还需要线程继续执行任务的哟
            if (min == 0 && ! workQueue.isEmpty())
                // 设置最少还需要一个线程
                min = 1;
            // ④ 获取线程池当前的线程数和至少的线程数比较,如果大于表示线程池还有线程,直接返回
            // 否则跳到 addWorker(null, false); 给线程池补充一个worker线程
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        // 给线程池补充一个worker线程
        addWorker(null, false);
    }
}
10.shutdown()
// SHUTDOWN : 不接收任务,但是执行 workerQueue 中的任务
public void shutdown() {
    // 加锁操作
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 检查权限
        checkShutdownAccess();
        // 修改运行状态改为 SHUTDOWN
        advanceRunState(SHUTDOWN);
        // 中断空闲的线程
        interruptIdleWorkers();
        // 钩子方法
        onShutdown(); 
    } finally {
        // 解锁操作
        mainLock.unlock();
    }
    // TODO - 看后面
    tryTerminate();
}
// CAS改变线程池状态
private void advanceRunState(int targetState) {
    // 死循环
    for (;;) {
        // 拿到 ctl
        int c = ctl.get();
        // 判断线程池是否至少处在了要改变的状态 rs >= targetState,是直接break 
        // 否则 CAS 改变线程池运行状态,如果失败继续下一次循环
        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 {
        // 循环 workers 集合
        for (Worker w : workers) {
            // 拿到线程对象
            Thread t = w.thread;
            // 如果线程未被中断,且 tryLock成功表示空闲线程(前面 w.lock执行任务时设置值,如果在执行任务,tryLock会失败)
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    // 中断线程
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    // unlock
                    w.unlock();
                }
            }
            // 如果只是一个,break
            if (onlyOne)
                break;
        }
    } finally {
        // 全局锁释放
        mainLock.unlock();
    }
}
11.shutdownNow()
// STOP : 不接收任务,也不执行 workerQueue 中的任务,可以拿到队列中的任务
public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    // 加锁操作
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 检查权限
        checkShutdownAccess();
        // 修改运行状态为 STOP
        advanceRunState(STOP);
        // 中断所有的线程
        interruptWorkers();
        // 取出队列中的任务进行返回
        tasks = drainQueue();
    } finally {
        // 解锁操作
        mainLock.unlock();
    }
    // TODO - 看后面
    tryTerminate();
    return tasks;
}
// 中断所有的线程
private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 循环全部中断
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}
void interruptIfStarted() {
    Thread t;
    // AQS的 state 状态值大于大于0时成立(防止线程池还没有启动就关闭的操作)
    // 线程不为null,且线程没有被中断过
    if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
        try {
            // 中断线程
            t.interrupt();
        } catch (SecurityException ignore) {
        }
    }
}
// 获取 workQueue 队列中的任务
private List<Runnable> drainQueue() {
    BlockingQueue<Runnable> q = workQueue;
    ArrayList<Runnable> taskList = new ArrayList<Runnable>();
    // 这里是实现了drainTo方法的情况,取出队列的任务添加到list并移除任务
    q.drainTo(taskList);
    // 子类可能没有实现drainTo方法,所以需要以下的操作
    if (!q.isEmpty()) {
        // 取出 workQueue 队列中的任务进行移除并添加到 list集合中进行返回
        for (Runnable r : q.toArray(new Runnable[0])) {
            if (q.remove(r))
                taskList.add(r);
        }
    }
    return taskList;
}
12.awaitTermination(…)
public boolean awaitTermination(long timeout, TimeUnit unit)
    throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    // 加锁操作
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (;;) {
            // 查看线程池运行状态是否 TERMINATED,是直接返回,表示线程池已经终结
            if (runStateAtLeast(ctl.get(), TERMINATED))
                return true;
            // 看下等待时间,小于等于不等待,直接返回
            if (nanos <= 0)
                return false;
            // 条件等待队列等待被唤醒 termination Condition 条件等待队列
            nanos = termination.awaitNanos(nanos);
        }
    } finally {
        // 解锁操作
        mainLock.unlock();
    }
}
13.tryTerminate()
// 销毁方法
final void tryTerminate() {
    for (;;) {
        // 当前 ctl
        int c = ctl.get();
        // 线程池是运行状态- 直接退出
        if (isRunning(c) ||
            // 线程池处在 TIDING/TERMINATED - 直接退出
            runStateAtLeast(c, TIDYING) ||
            // 线程池状态处于 SHUTDOWN,此时不接收任务,但执行队列中的任务,判断队列是否为空
            // 队列不为空,还有任务要执行 - 直接退出
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        // 线程池线程数不为 0 表示还有其他线程
        // 每个线程都会走这里,这里只需要确保一个线程继续往下走即可
        if (workerCountOf(c) != 0) {
            // 中断空闲线程 - 只中断一个[因为需要执行后续的代码,线程不能全部退出]
            interruptIdleWorkers(ONLY_ONE);
            return;
        }
        // 加锁
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // CAS 将线程池运行状态改为 TIDYING
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    // 执行 terminated() 方法
                    terminated();
                } finally {
                    // CAS 将线程池运行状态改为 TERMINATED
                    ctl.set(ctlOf(TERMINATED, 0));
                    // 唤醒 TERMINATED 状态的线程 awaitTerminated
                    termination.signalAll();
                }
                return;
            }
        } finally {
            // 解锁
            mainLock.unlock();
        }
    }
}

六、ScheduledThreadPoolExecutor

0、Why
  • ThreadPoolExecutor

需要有存入线程的容器:HashSet

需要有存放任务的容器:BlockingQueue

  • 由于工作队列是多线程共享,也即线程容器中的线程都需要访问,所以这个队列必须是多线程并发安全的
  • 由于工作线程在没有任务可以执行的时候,那么需要阻塞,所以这个队列要支持没有任务的时候让线程阻塞

因此:BlockingQueue 满足

  • ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor

  • 由于Scheduled线程池需要进行任务调度,且需要延迟执行,那么任务必须能够排队执行

  • 由于放入的任务不一定能够立即执行,所有还需要存入队列,然后获取,看看是否满足执行条件:时间是否满足

因此:

  • ThreadPoolExecutor 原有部分逻辑不满足此需求,所以需要继承TPE并且增加自己的执行逻辑
  • 由于任务需要排队且时间排序,那么需要实现自己的 BlockingQueue:DelayedWorkQueue
1、How to use
public static void main(String[] args) throws InterruptedException {
    ScheduledExecutorService scheduledExecutorService =
        new ScheduledThreadPoolExecutor(2);
    // 延迟执行1次
    scheduledExecutorService.schedule(() ->
                                      System.out.println(new Date()),2,TimeUnit.SECONDS);
    /**
  * Sat Jun 19 15:48:47 CST 2021
  * Sat Jun 19 15:48:49 CST 2021
  * Sat Jun 19 15:48:51 CST 2021
  */
    // 周期执行:任务开始时开始计时
    scheduledExecutorService.scheduleAtFixedRate(() -> {
        System.out.println(new Date());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    },0,2,TimeUnit.SECONDS);
    /**
 * Sat Jun 19 15:48:03 CST 2021
 * Sat Jun 19 15:48:07 CST 2021
 * Sat Jun 19 15:48:11 CST 2021
 */
    // 周期执行:任务结束时开始计时
    scheduledExecutorService.scheduleWithFixedDelay(() -> {
        System.out.println(new Date());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    },0,2,TimeUnit.SECONDS);
}
2、ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor,主要用来在给定的延迟之后运行任务,或者定期执行任务

  • 使用自定义任务类型 ScheduledFutureTask ,即使不需要调度的任务也会被认为是延时为0的延时任务
  • 使用自定义的队列 DelayedWorkQueue,DelayQueue 是无界队列,与 ThreadPoolExecutor 比较缺少容量的限制、corePoolSize 、maximumPoolSize,有效的简化了一些执行机制
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOMqU0go-1633849992233)(.1624343877268.png)]
3、ScheduledFutureTask 任务对象
// 比较器
public interface Delayed extends Comparable<Delayed> {
  // 获取延迟时间
  long getDelay(TimeUnit unit);
}
public interface ScheduledFuture<V> extends Delayed, Future<V> {
}
public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
  // 是否周期性执行
  boolean isPeriodic();
}
private class ScheduledFutureTask<V>
      extends FutureTask<V> implements RunnableScheduledFuture<V> {
 // 任务序列号
    private final long sequenceNumber;
 // 任务执行的时间 - 单位毫秒
    private long time;
 // 重复执行任务的周期,正数表示固定周期执行,负数表示固定延时执行,0表示不是周期任务
    private final long period;
 // 任务包装
    RunnableScheduledFuture<V> outerTask = this;
 // 延时队列的索引号
    int heapIndex;
}

主要方法:

  • 任务对象大小比较 - compareTo(Delayed other)
  • run()
  • cancel()

构造器:

// 构造定时任务,在 ns 纳秒后执行,执行完成后结果为 result
ScheduledFutureTask(Runnable r, V result, long ns) {
  super(r, result);
  this.time = ns;
  this.period = 0;
  this.sequenceNumber = sequencer.getAndIncrement();
}
// 构造一个周期任务,在 ns 纳秒后执行,每隔 period 纳秒执行一次
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
  super(r, result);
  this.time = ns;
  this.period = period;
  this.sequenceNumber = sequencer.getAndIncrement();
}
// 构造一个 Callable 定时任务,在 ns 纳秒后执行
ScheduledFutureTask(Callable<V> callable, long ns) {
  super(callable);
  this.time = ns;
  this.period = 0;
  this.sequenceNumber = sequencer.getAndIncrement();
}
4、接口方法
public interface ScheduledExecutorService extends ExecutorService {
    // 延迟 delay 时间执行任务
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
    // 延迟 delay 时间执行任务
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay, TimeUnit unit);
    // 固定频率周期执行任务 - 任务开始时开始计时
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
    // 固定延时周期执行任务 - 任务结束时开始计时
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);
}
6、源码分析 - 几个主要的方法
1.构造器
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          // 无界延迟队列
          new DelayedWorkQueue());
}
2.schedule(…)
public ScheduledFuture<?> schedule(Runnable command,
                                   long delay,
                                   TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    RunnableScheduledFuture<?> t = decorateTask(command,
                                                new ScheduledFutureTask<Void>(command, null,
                                                                              triggerTime(delay, unit)));
    delayedExecute(t);
    return t;
}
3.take()
// 任务获取
public RunnableScheduledFuture<?> take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        for (;;) {
            // 任务数组获取任务 - 小顶堆
            RunnableScheduledFuture<?> first = queue[0];
            // 任务不存在
            if (first == null)
                // 线程等待
                available.await();
            // 任务存在
            else {
                // 任务延时时间
                long delay = first.getDelay(NANOSECONDS);
                // 已经超时
                if (delay <= 0)
                    // 弹出任务 并根据延时时间大小调整堆
                    return finishPoll(first);
                // 任务还没到时间
                first = null;
                // 任务线程不为空,去等待
                if (leader != null)
                    available.await();
                else {
                    // 任务线程为空,设置任务线程为当前线程
                    Thread thisThread = Thread.currentThread();
                    leader = thisThread;
                    try {
                        // 延时等待
                        available.awaitNanos(delay);
                    } finally {
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        // 任务线程为空,且有任务,唤醒等待线程
        if (leader == null && queue[0] != null)
            available.signal();
        lock.unlock();
    }
}
4.scheduleAtFixedRate(…)
// 固定频率周期任务 - 任务开始时计时
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                       long initialDelay,
                       long period,
                       TimeUnit unit) {
 // 基本判空
 if (command == null || unit == null)
   throw new NullPointerException();
 // 大于0 表示固定频率执行任务,小于0 表示固定延时任务,等于0 表示非周期任务,不合法
 if (period <= 0)
    throw new IllegalArgumentException();
 // 任务封装
 ScheduledFutureTask<Void> sft =
   new ScheduledFutureTask<Void>(command,
                   null,
                   triggerTime(initialDelay, unit),
                   unit.toNanos(period));
 RunnableScheduledFuture<Void> t = decorateTask(command, sft);
 sft.outerTask = t;
 // 延时执行任务
 delayedExecute(t);
 return t;
}
// 延时执行任务
private void delayedExecute(RunnableScheduledFuture<?> task) {
 // 线程池关闭了,拒绝任务
 if (isShutdown())
   reject(task);
 else {
   // 添加任务到队列
    super.getQueue().add(task);
    // 线程池关闭了
    if (isShutdown() &&
      // 且周期任务不能马上执行
      !canRunInCurrentRunState(task.isPeriodic()) &&
      // 从队列移除任务成功
      remove(task))
      // 取消任务
      task.cancel(false);
    else
      // 确保线程预先启动
      ensurePrestart();
 }
}
// 添加任务线程
void ensurePrestart() {
 // 线程数+1
 int wc = workerCountOf(ctl.get());
 // 线程数小于核心线程数,添加核心线程
 if (wc < corePoolSize)
    addWorker(null, true);
 else if (wc == 0) 
    // 添加非核心线程
    addWorker(null, false);
}
5.scheduleWithFixedDelay(…)
// 固定延时周期任务 - 任务执行完成后开始计时 delay 周期执行
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit) {
    // 基本判空
    if (command == null || unit == null)
        throw new NullPointerException();
    // 延时时间 <= 0 不合法
    if (delay <= 0)
        throw new IllegalArgumentException();
    // 任务封装
    ScheduledFutureTask<Void> sft =
        new ScheduledFutureTask<Void>(command,
                                      null,
                                      triggerTime(initialDelay, unit),
                                      unit.toNanos(-delay));
    RunnableScheduledFuture<Void> t = decorateTask(command, sft);
    sft.outerTask = t;
    // 延时执行
    delayedExecute(t);
    return t;
}
6.ScheduledThreadPoolExecutor.run()
// 执行体
public void run() {
    // period != 0 是否周期任务,true表示周期性延迟任务,false表示一次性延迟任务
    boolean periodic = isPeriodic();
    // 是否可以运行延迟任务,返回true表示可以,false表示不行,取反后,表示如果不能运行则取消任务
    if (!canRunInCurrentRunState(periodic))
        // 取消任务
        cancel(false);
    // 一次性任务直接执行
    else if (!periodic)
        ScheduledFutureTask.super.run();
    // 周期任务:runAndReset 执行包装后的任务,调用 call 方法
    else if (ScheduledFutureTask.super.runAndReset()) {
        // 设置下一次周期任务执行时间
        setNextRunTime();
        // 重新将周期任务放入队列
        reExecutePeriodic(outerTask);
    }
}
// 取消任务
public boolean cancel(boolean mayInterruptIfRunning) {
    // 中断任务
    boolean cancelled = super.cancel(mayInterruptIfRunning);
    // removeOnCancel 默认 false,除非手动设置,表示中断任务的同时将其从队列中移除
    if (cancelled && removeOnCancel && heapIndex >= 0)
        remove(this);
    return cancelled;
}
// 设置下一次周期任务执行时间
private void setNextRunTime() {
    // period > 0 固定频率执行 period = 0 一次性任务 period < 0 固定延时执行
    long p = period;
    // period > 0 加上固定时间
    if (p > 0)
        time += p;
    else 
        // period < 0
        // 设置延迟任务的下一次触发的时间
        time = triggerTime(-p);
}
// 重新将周期任务放入队列
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
    // 当前线程池运行状态允许
    if (canRunInCurrentRunState(true)) {
        // 周期任务重新入队
        super.getQueue().add(task);
        // 再次检查,如果不允许,那么移除当前任务并取消任务
        if (!canRunInCurrentRunState(true) && remove(task))
            task.cancel(false);
        else
            ensurePrestart();
    }
}

七、ForkJoinPool

0、Why
  • 任务分支合并需求:一个大任务分成多个小任务,小任务执行完后依次返回

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Us5fnU7-1633849989836)(.1624344857633.png)]

  • 如果使用 TPE 去实现这个逻辑,需要业务方自己获取 Future做处理,异常麻烦

  • 当线程池的任务,由于线程池满了,这时需要放入到队列中等待,而大任务只能干等待,什么也做不了,此时,这个线程阻塞在这里就是一种浪费

因此:原有线程池满足不了我们的需求,且扩展 TPE 的代码也无济于事,需要构建一个线程池来满足以上需求,以更高效的执行任务

1、How to use
public static void main(String[] args) throws InterruptedException {
    ForkJoinPool forkJoinPool = new ForkJoinPool();
    forkJoinPool.submit(() -> System.out.println("hello world"));
    forkJoinPool.shutdown();
    forkJoinPool.awaitTermination(1, TimeUnit.DAYS);
}
2、源码分析
1.整体架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vhcDpD7g-1633849989838)(.1624430185493.png)]

  • 数组下标奇偶性来判断队列是外部提交队列还是工作窃取队列
  • 偶数下标:外部提交队列
  • 奇数下标:工作窃取队列
  • 双端队列
  • TOP 头部存入任务
  • 取任务与 mode 有关 asyncMode ? FIFO_QUEUE : LIFO_QUEUE
  • FIFO_QUEUE - TOP拿取任务
  • LIFO_QUEUE - BASE拿取任务 [默认方式]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnqugMeo-1633849989840)(.1624431782307.png)]

  • 队列空和满 (top 和 base 指针只增不减)
  • q.base - q.top = 0 队列为空
  • q.base - q.top < 0 队列不为空
  • a.length > q.top + 1 - q.base 队列没满
2.变量
// ctl : AC + TC
volatile long ctl;   // main pool control
// 线程池运行状态
volatile int runState;        // lockable status
// 存储并行度parallelism和执行模式[FIFO_QUEUE/LIFO_QUEUE] 
// 高16位存储执行模式,低16位存储并行度
final int config;          // parallelism, mode
// runState bits: SHUTDOWN must be negative, others arbitrary powers of two
// 线程池运行状态:rs < 0 表示 SHUTDOWN
private static final int RSLOCK   = 1;
private static final int RSIGNAL  = 1 << 1; // 2
private static final int STARTED  = 1 << 2; // 4
private static final int STOP    = 1 << 29; // 30 位为1
private static final int TERMINATED = 1 << 30; // 31 位为1
private static final int SHUTDOWN  = 1 << 31; // 32 位为1,小于0,不接受外部任务
// 活动线程数 Active counts
private static final int AC_SHIFT  = 48;
// 用于对 ctl 高32位高16位+1,也即活动线程数 AC + 1
private static final long AC_UNIT  = 0x0001L << AC_SHIFT; 
// 用于取 ctl 高32位高16位的值,也即活动线程数 AC
private static final long AC_MASK  = 0xffffL << AC_SHIFT; 
// 总线程数 Total counts
private static final int TC_SHIFT  = 32;
// 用于对 ctl 高32 位低16位+1,也即总线程数 TC + 1
private static final long TC_UNIT  = 0x0001L << TC_SHIFT;
// 用于取 ctl 高32位低16位的值,也即总线程数 TC
private static final long TC_MASK  = 0xffffL << TC_SHIFT;
private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
// Mode bits for ForkJoinPool.config and WorkQueue.config
// 用于取执行模式 mode 的值 [FIFO_QUEUE/LIFO_QUEUE]
static final int MODE_MASK  = 0xffff << 16; // top half of int
// 执行模式 LIFO_QUEUE,默认值,从 TOP 取任务
static final int LIFO_QUEUE  = 0;
// 执行模式 FIFO_QUEUE,int值第17位为1 - 从 BASE 取任务
static final int FIFO_QUEUE  = 1 << 16;
3.构造器
// 无参构造器
public ForkJoinPool() {
    // MAX_CAP = 0x7fff = 32767 ; 默认最大线程数 = CPU核心数
    this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
         defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(int parallelism,
                    ForkJoinWorkerThreadFactory factory, // 线程工厂
                    UncaughtExceptionHandler handler, // 线程异常处理器
                    boolean asyncMode) { // 执行模式:异步/同步。默认 false
    this(checkParallelism(parallelism), // 非法参数校验
         checkFactory(factory),
         handler,
         // static final int LIFO_QUEUE  = 0;
         // static final int FIFO_QUEUE  = 1 << 16;
         asyncMode ? FIFO_QUEUE : LIFO_QUEUE, // 取任务的方式:base 和 top
         "ForkJoinPool-" + nextPoolId() + "-worker-");
    checkPermission();
}
// 最终构造器
private ForkJoinPool(int parallelism,
                     ForkJoinWorkerThreadFactory factory,
                     UncaughtExceptionHandler handler,
                     int mode,
                     String workerNamePrefix) {
    this.workerNamePrefix = workerNamePrefix;
    this.factory = factory;
    this.ueh = handler;
    // SMASK = 0x0000 ffff 将 config 的低16位用于存放并行度,高16位存储执行模式
    this.config = (parallelism & SMASK) | mode;
    // 以并行度64为例 AC 1111111111000000  TC: 1111111111000000
    long np = (long)(-parallelism); // offset ctl counts
    // 计算 ctl 的值,AC + TC :高32位的值
    this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
4.提交任务
  • submit(…)
// 将任务封装成FJT,因为FJP只执行FJT的任务
public ForkJoinTask<?> submit(Runnable task) {
   ForkJoinTask<?> job;
   if (task instanceof ForkJoinTask<?>)
       job = (ForkJoinTask<?>) task;
   else
       job = new ForkJoinTask.AdaptedRunnableAction(task);
   externalPush(job); // 核心提交任务方法
   return job;
}

将任务封装为 FJP 的任务 ForkJoinTask

  • externalPush(…)
final void externalPush(ForkJoinTask<?> task) {
   WorkQueue[] ws; WorkQueue q; int m;
   // 获取随机数 r
   int r = ThreadLocalRandom.getProbe();
   int rs = runState;
   // 表示任务队列数组已被初始化,且找到的队列也已初始化且没有满,将任务放入队列,唤醒线程执行
   if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 &&
       (q = ws[m & r & SQMASK]) != null && r != 0 && rs > 0 &&
       U.compareAndSwapInt(q, QLOCK, 0, 1)) {
       ForkJoinTask<?>[] a; int am, n, s;
       if ((a = q.array) != null &&
           (am = a.length - 1) > (n = (s = q.top) - q.base)) {
           int j = ((am & s) << ASHIFT) + ABASE;
           U.putOrderedObject(a, j, task);
           U.putOrderedInt(q, QTOP, s + 1);
           U.putIntVolatile(q, QLOCK, 0);
           // n<=1 表示队列中最多有一个任务,唤醒线程执行任务
           if (n <= 1)
               signalWork(ws, q);
           return;
       }
       U.compareAndSwapInt(q, QLOCK, 1, 0);
   }
   // 提交任务核心方法
   externalSubmit(task);
}

生成随机数,先判断任务队列是否初始化了(优化)、没有则继续调用任务提交方法

  • externalSubmit(…)
private void externalSubmit(ForkJoinTask<?> task) {
   int r;                  // initialize caller's probe
   // 取随机数
   if ((r = ThreadLocalRandom.getProbe()) == 0) {
       ThreadLocalRandom.localInit();
       r = ThreadLocalRandom.getProbe();
   }
   // 死循环,会执行多次,每次只走一个分支
   for (;;) {
       WorkQueue[] ws; WorkQueue q; int rs, m, k;
       boolean move = false;
       // 判断 rs 线程池运行状态是否 SHUTDOWN 了
       if ((rs = runState) < 0) {
           tryTerminate(false, false);   
           throw new RejectedExecutionException();
       }
       // STARTED状态位没有置位,所以需要初始化
       // 注意:如果该分支不执行,但是由于||运算符的存在,这里ws和m变量已经初始化
       else if ((rs & STARTED) == 0 ||  
                ((ws = workQueues) == null || (m = ws.length - 1) < 0)) {
           int ns = 0;
           // 加锁
           rs = lockRunState();
           try {
               // 再次判断了一下STARTED状态位
               // 因为多线程操作,可能上面判断过后已经被别的线程初始化了,所以没必要再进行CAS
               if ((rs & STARTED) == 0) {
                   U.compareAndSwapObject(this, STEALCOUNTER, null,
                                          new AtomicLong());
                   // p 是并行度:工作线程的数量
                   int p = config & SMASK; // ensure at least 4 slots
                   int n = (p > 1) ? p - 1 : 1; // n 最小为 1
                   // 这里取传入的数最近的2的次幂,即队列数组保证是2的次幂长度
                   // 目的是为了使用奇偶下标区分外部提交队列和工作窃取队列
                   n |= n >>> 1; n |= n >>> 2; n |= n >>> 4;
                   n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1;
                   // 工作队列数组初始化(外部提交队列+工作窃取队列)
                   workQueues = new WorkQueue[n];
                   // 初始化成功,那么此时状态修改为STARTED状态
                   ns = STARTED;
               }
           } finally {
               // 最后释放锁
               unlockRunState(rs, (rs & ~RSLOCK) | ns);
           }
       }
       // 在上一个分支执行完毕后,第二次循环将会到达这里。由于咱们的算法是用了一个全局队列:workQueues来存储两钟队列:外部提交队列、工作窃取队列,那么这时应该去找到这个任务放在哪个外部提交队列里面。通过上面获取的随机种子r,来找到应该放在哪里?SQMASK = 1111110,所以由SQMASK的前面的1来限定长度,末尾的0来表明,外部提交队列一定在偶数位
       else if ((q = ws[k = r & m & SQMASK]) != null) {
           // 由于当前提交队列是外部提交队列,那么一定会有多线程共同操作,那么为了保证并发安全,那么这里需要上锁,也即对当前提交队列进行锁定
           if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) {
               // 取外部提交队列的保存任务的数组array
               ForkJoinTask<?>[] a = q.array;
               // 栈顶指针 top
               int s = q.top;
               boolean submitted = false; 
               try {           
                   // 当前任务数组已经初始化 且 数组没有满
                   if ((a != null && a.length > s + 1 - q.base) ||
                       // 如果前面不成立,也即 数组没有初始化或数组满了
                       // 那么这里初始化数组或者扩容
                       (a = q.growArray()) != null) {
                       // 扩容之后,开始存放任务
                       int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
                       U.putOrderedObject(a, j, task); // 放任务
                       U.putOrderedInt(q, QTOP, s + 1); // 栈顶指针 top+1
                       // 为什么这里需要怎么写?注意:qtop和q.array没有volatile修饰
                       submitted = true;
                   }
               } finally {
                   // qlock是volatile的,由于volatile的特性,这个操作CAS出去,那么qlock线程可见,必然上面的task和qtop可见,且有序。
                   U.compareAndSwapInt(q, QLOCK, 1, 0);
               }
               if (submitted) {
                   // 由于添加成功了,但是,没有工作线程,那么这时通过signalWork,创建工作线程并执行
                   signalWork(ws, q);
                   return;
               }
           }
           // 由于当前线程无法获取初始计算的提交队列的锁,那么这时发生了线程竞争,那么设置move标志位,让线程在下一次循环的时候,重新计算随机数,让它寻找另外的队列。
           move = true;          
       }
       // 如果找到的这个wq没有被创建,那么创建他,但是,这里的RSLOCK的判断,在于,当没有别的线程持有RSLOCK的时候,才会进入。这是由于RSLOCK主管,runstate,可能有别的线程把状态改了,根本不需要再继续work了
       else if (((rs = runState) & RSLOCK) == 0) { 
           // 创建外部提交队列,由于ForkJoinWorkerThread FJWT为null,所以为外部提交队列
           q = new WorkQueue(this, null);
           // r为什么保存为hint,r是随机数,通过r找到当前外部提交队列,处于WQS的索引下标
           q.hint = r;
           // SHARED_QUEUE = 1 << 31;这里就是将整形int的符号位置1,所以为负数,SHARED_QUEUE表明当前队列是共享队列(外部提交队列)。而k为当前wq处于WQS中的索引下标
           q.config = k | SHARED_QUEUE;
           // 由于当前wq并没有进行扫描任务,所以扫描状态位无效状态INACTIVE
           q.scanState = INACTIVE;
           // 对wqs上锁操作:就是将上面的队列放入到WQS的偶数位中
           rs = lockRunState(); 
           // 确保线程池处于运行状态
           // 由于可能两个线程同时进来操作,只有一个线程持有锁,那么只允许一个线程放创建的队列,但是这里需要注意的是:可能会有多个线程创建了WorkQueue,但是只有一个能成功
           if (rs > 0 && (ws = workQueues) != null &&
               k < ws.length && ws[k] == null)
               // 将wq放入全局队列WQS中
               ws[k] = q;
           // 解锁
           unlockRunState(rs, rs & ~RSLOCK);
       }
       // 发生竞争时,让当前线程选取其他的wq来重试
       else
           move = true;          
       if (move)
           // 获取下一个不同的随机数,重新进行尝试
           r = ThreadLocalRandom.advanceProbe(r);
   }
}

初始化任务队列数组,数组大小为2的次幂,并将任务保存到外部提交队列

5.创建工作窃取队列并绑定线程(FJWT)
  • signalWork(…)
// 上面的内容,都是初始化,放任务,但是执行线程没有啊,谁来执行这个放入到了外部提交队列中的任务。
final void signalWork(WorkQueue[] ws, WorkQueue q) {
   long c; int sp, i; WorkQueue v; Thread p;
   // 符号位没有溢出:最高16位为AC,代表了工作活跃的线程数没有达到最大值
   while ((c = ctl) < 0L) {            
       // ctl的低32位代表了INACTIVE数。若此时sp=0,代表了没有空闲线程
       if ((sp = (int)c) == 0) {
           // ADD_WORKER = 0x0001L << (TC_SHIFT + 15) TC的最高位是不是0,若不是0,那么FJP中的工作线程代表了没有达到最大线程数
           if ((c & ADD_WORKER) != 0L) 
               // 尝试添加工作线程
               tryAddWorker(c);
           break;
       }
       // 此时,代表了空闲线程不为null
       // 此时FJP的状态为NOT STARTED,TERMINATED
       if (ws == null)              
           break;
       // SMASK = 0xffff 取sp的低16位 TERMINATED
       if (ws.length <= (i = sp & SMASK))     
           break;
       // ctl低32位的低16位是不是存放了INACTIVE线程在wqs的下标i TERMINATING
       if ((v = ws[i]) == null)          
           break;
       // SS_SEQ = 1 << 16; ctl低32位的高16位是不是存放了版本计数 version count  INACTIVE= 1 << 31
       int vs = (sp + SS_SEQ) & ~INACTIVE;    
       int d = sp - v.scanState;         
       // 把获取到的INACTIVE的线程,也即空闲线程唤醒,那么唤醒后,是不是应该对AC + 1(加1操作(c + AC_UNIT)),UC_MASK为高32位1,低32位0,所以(UC_MASK & (c + AC_UNIT))代表了,保留ctl的高32位值,也即AC+1和TC值
       long nc = (UC_MASK & (c + AC_UNIT)) | 
           // SP_MASK为高32位0,低32位1,所以保留了低32位的值,v.stackPred 代表了一个出栈操作,让低32位的低16位更新为唤醒线程的下一个线程
           (SP_MASK & v.stackPred);
       // 此时的nc就是计算好的下一个ctl,next ctl -> n
       if (d == 0 && U.compareAndSwapLong(this, CTL, c, nc)) {// CAS 替换CTL
           // 记录版本信息放入scanState,此时为正数
           v.scanState = vs;       
           if ((p = v.parker) != null)
               // 唤醒工作线程
               U.unpark(p);
           break;
       }
       // 队列为空,直接退出。由于队列是多线程并发的,所以有可能放入其中的任务已经被其他线程获取,所以此时队列为空
       if (q != null && q.base == q.top)     
           break;
   }
}

唤醒空闲线程执行提交的任务,如果没有空闲线程则创建线程执行任务

  • tryAddWorker(…)
// 尝试添加工作线程
private void tryAddWorker(long c) {
   boolean add = false;
   do {
       // active count +1 活跃线程数加1,此时只保留了高32位的高16位信息
       long nc = ((AC_MASK & (c + AC_UNIT)) |
                  // total count +1 总线程数加1,此时只保留了高32位的低16位信息
                  (TC_MASK & (c + TC_UNIT)));
       // 此时nc为next ctl,也即活跃线程数+1,总线程数+1
       // ctl没有被其他线程改变
       if (ctl == c) {
           int rs, stop;
           // 上锁并检查FJP的状态是否为STOP
           if ((stop = (rs = lockRunState()) & STOP) == 0)
               // 更新ctl的值。add表明是否添加成功
               add = U.compareAndSwapLong(this, CTL, c, nc);
           // 解锁
           unlockRunState(rs, rs & ~RSLOCK);
           // 线程池已经停止
           if (stop != 0)
               break;
           // 如果ac和tc添加1成功,也即nc替换成功,那么创建工作线程
           if (add) {
               // 创建工作线程
               createWorker();
               break;
           }
       }
   } while (((c = ctl) & ADD_WORKER) != 0L // 没有达到最大线程数
            && (int)c == 0); // 低32位0,有空闲线程
}

活跃线程数+1:AC+1;总线程数+1:TC+1

  • createWorker(…)
// 创建工作线程
private boolean createWorker() {
   ForkJoinWorkerThreadFactory fac = factory;
   Throwable ex = null;
   ForkJoinWorkerThread wt = null;
   try {
       // 从线程工厂中,创建线程 FJWT 绑定工作窃取队列
       if (fac != null && (wt = fac.newThread(this)) != null) {
           // 并启动线程 - 执行run方法
           wt.start();
           return true;
       }
   } catch (Throwable rex) {
       ex = rex;
   }
   // 如果创建出现异常,将ctl前面加的1回滚
   deregisterWorker(wt, ex);
   return false;
}

真正的创建线程并启动线程,出现异常调用deregisterWorker方法对前面的AC/TC-1

  • ForkJoinWorkerThreadFactory 线程工厂
// 默认线程工厂
static final class DefaultForkJoinWorkerThreadFactory
   implements ForkJoinWorkerThreadFactory {
   public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
       return new ForkJoinWorkerThread(pool); // 直接new ForkJoinWorkerThread
   }
}

FJP 默认线程工厂

  • ForkJoinWorkerThread
// FJWT的构造器
protected ForkJoinWorkerThread(ForkJoinPool pool) {
   super("aForkJoinWorkerThread");
   // 保存对外的FJP的引用 
   this.pool = pool; 
   // 将自己注册到FJP中,其实就是保存到FJP的奇数位中
   this.workQueue = pool.registerWorker(this); 
}

FJP 的线程封装类 ForkJoinWorkerThread

  • registerWorker(…)
// 将自己注册到FJP中
final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
   UncaughtExceptionHandler handler;
   // FJWT 设置为守护线程
   wt.setDaemon(true);
   // 如果设置了线程的异常处理器,那么设置
   if ((handler = ueh) != null)
       wt.setUncaughtExceptionHandler(handler);
   // 创建工作线程,注意:创建外部提交队列时: WorkQueue w = new WorkQueue(this, null)
   // 这里创建的是工作窃取队列
   WorkQueue w = new WorkQueue(this, wt);
   // 创建的工作队列w所保存在wqs的索引下标
   int i = 0;            
   // 从config中取设置的工作模式 mode:FIFO、LIFO
   int mode = config & MODE_MASK;
   // 加锁
   int rs = lockRunState();
   try {
       WorkQueue[] ws; int n;          
       // 日常判空操作
       if ((ws = workQueues) != null && (n = ws.length) > 0) {
           // indexSeed = 0,SEED_INCREMENT = 0x9e3779b9 ,大质数减少hash碰撞
           int s = indexSeed += SEED_INCREMENT; 
           // wqs长度-1,用于取模运算
           int m = n - 1;
           // 找存放w的下标 - 类似取模运算
           // 注意:这里 i 的值一定是奇数
           i = ((s << 1) | 1) & m;  
           // 发生了碰撞
           if (ws[i] != null) {         
               int probes = 0;          
               // 发生碰撞二次寻址 EVENMASK = 0xfffe;
               // step保证为偶数:n是2的次幂,n>>>1 高位后全1,&上低位为0的0xfffe必为偶数
               int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
               // (i + step) & m 计算WQS的索引下标:i 一定是奇数,step一定是偶数
               // 一个奇数+偶数一定等于奇数,也即找到工作窃取队列所在的槽位
               while (ws[i = (i + step) & m] != null) {
                   // 寻址达到了极限,那么扩容
                   if (++probes >= n) {
                       // 扩容容量为2倍
                       workQueues = ws = Arrays.copyOf(ws, n <<= 1);
                       m = n - 1;
                       probes = 0;
                   }
               }
           }
           // s作为随机数保存在wq的hint中
           w.hint = s;     
           // 此config是WorkQueue的保存索引下标 + 模式
           w.config = i | mode;
           // scanState为volatile,此时对它进行写操作,ss写成功,上面的变量一定可见,且不会和下面的ws[i]赋值发生重排序。注意这里的scanState就变成了odd,也即奇数,所以要开始扫描获取任务并执行啦
           w.scanState = i; 
           // 放入全局队列中
           ws[i] = w;
       }
   } finally {
       // 解锁
       unlockRunState(rs, rs & ~RSLOCK);
   }
   wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
   return w;
}

创建工作窃取队列 new WorkQueue(this, wt) ,绑定线程FJWT,找到全局 workQueues 数组的奇数下标位置,将其w存放到这个位置上,如果发现已经存在了,则重新计算workQueues的槽位奇数位下标位置,如果计算了一轮还没有找到,则表示需要扩容了,扩容为原来的2倍,扩容后再次计算槽位

6. 执行任务
  • run()
// FJWT 的run方法,执行体
public void run() {
   // 只run一次。array用于存放FJT,那么这里用它作为标识,来确保FJWT只run一次
   if (workQueue.array == null) { 
       Throwable exception = null;
       try {
           // run之前执行钩子函数
           onStart();
           // 核心执行方法
           pool.runWorker(workQueue);
       } catch (Throwable ex) {
           exception = ex;
       } finally {
           try {
               // run之后执行钩子函数
               onTermination(exception);
           } catch (Throwable ex) {
               // 如果异常为空,则保存这里的异常,否则异常为上面的catch块异常。其实呢就是一句话:保存最先发生的异常
               if (exception == null)
                   exception = ex;
           } finally {
               // 线程退出后,进行状态还原
               pool.deregisterWorker(this, exception);
           }
       }
   }
}

FJWT的执行体,确保run方法只执行一次,提供钩子方法onStart、onTermination,供开发者进行扩展

  • runWorker(…)
// FJP中的真正处理FJWT工作的函数
final void runWorker(WorkQueue w) {
   w.growArray();    // 分配array:初始化或扩容
   int seed = w.hint;    // 取随机数
   int r = (seed == 0) ? 1 : seed; // 避免出现0
   // 循环获取任务并执行,直到显示退出
   for (ForkJoinTask<?> t;;) {
       if ((t = scan(w, r)) != null) // 扫描可执行任务 核心扫描方法 scan
           w.runTask(t); // 拿到任务之后开始执行
       else if (!awaitWork(w, r)) // 如果没有任务可执行,那么awaitWork等待任务执行
           break;
       // 异或算法,基于上一个随机数r,计算下一个伪随机数
       r ^= r << 13; r ^= r >>> 17; r ^= r << 5; 
   }
}

分配任务数组,循环扫描队列中的任务,有任务就执行,没有任务就等待

  • growArray()
// WorkQueue类中用于初始化或者增长array函数
final ForkJoinTask<?>[] growArray() {
   ForkJoinTask<?>[] oldA = array;
   //oldA存在,那么进行二倍长度扩容,否则size为初始化大小INITIAL_QUEUE_CAPACITY= 1<<13
   int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
   // 如果扩容之后,超过最大容量MAXIMUM_QUEUE_CAPACITY = 1<<26;也即64M,抛出异常
   if (size > MAXIMUM_QUEUE_CAPACITY)
       throw new RejectedExecutionException("Queue capacity exceeded");
   int oldMask, t, b;
   // 创建新的array数组
   ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
   // 扩容后,将旧的array中的任务放入到新的数组中
   // 面试题:为什么这里手动复制,而不用更快速的复制?System.arraycopy?面的是什么??如何保证数组中的元素的可见性?getObjectVolatile(数组的首地址,偏移量)
   if (oldA != null && (oldMask = oldA.length - 1) >= 0 &&
       (t = top) - (b = base) > 0) {
       int mask = size - 1;
       do { 
           ForkJoinTask<?> x;
           // 注意:这里从base引用开始取任务
           int oldj = ((b & oldMask) << ASHIFT) + ABASE;
           int j  = ((b &  mask) << ASHIFT) + ABASE;
           x = (ForkJoinTask<?>)U.getObjectVolatile(oldA, oldj);// volatile 语义 1
           if (x != null &&
               // 这里为何使用CAS?因此由于队列是工作窃取队列,可能有别的线程持有old数组引用,正在通过base引用窃取尾部任务
               U.compareAndSwapObject(oldA, oldj, x, null))
               U.putObjectVolatile(a, j, x); // volatile 语义 2
       } while (++b != t); // 循环,直到转移成功
   }
   return a;
}

任务数组初始化或扩容,扩容的话将旧数组中的数据放入到新数组中

  • scan(…)
// FJP中,在FJWT进行扫描获取任务执行。w为当前FJWT所处队列,r为随机数
private ForkJoinTask<?> scan(WorkQueue w, int r) {
   WorkQueue[] ws; int m;
   // 日常判空
   if ((ws = workQueues) != null && (m = ws.length - 1) > 0 && w != null) {
       // 保存初始时的扫描状态
       int ss = w.scanState;           
       // 扫描获取任务。origin初始为随机数取模的下标,k初始为origin。
       // 由于在扫描过程中,可能有别的线程添加获取等等操作,那么我怎么样让当前FJWT返回呢?不可能一直在这扫描吧,实在是没有任务了,那么必须退出,避免造成性能损耗,那么问题就变为:如何发现当前没有可执行的任务呢?(这叫推理学习,记忆方式),所以采用oldSum和checkSum来判断整个wqs是否处于稳定状态,也即没有别的线程再往里添加任务了,而且经历过一个周期,没有扫描到可执行任务,即可退出。
       for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) {
           WorkQueue q; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
           int b, n; long c;
           // 在wqs中找到了一个不为空的队列。那么看看有没有可以获取任务
           if ((q = ws[k]) != null) {
               // 由于放任务将会操作top指针,初始时,base等于top,每添加一个任务,top加1,所以随着任务的添加,那么此时base落后于top,所以base - top < 0 表明队列有任务
               if ((n = (b = q.base) - q.top) < 0 &&
                   // 队列中的任务数组array不为空,表明有任务可以获取
                   (a = q.array) != null) { 
                   // 取array索引下标base的偏移地址
                   long i = (((a.length - 1) & b) << ASHIFT) + ABASE;
                   if ((t = ((ForkJoinTask<?>)
                             U.getObjectVolatile(a, i))) != null && // 任务存在
                       q.base == b) { // base引用没有被改变,也即任务没有被取走
                       if (ss >= 0) { // 如果扫描状态正常
                           // CAS取任务
                           if (U.compareAndSwapObject(a, i, t, null)) {
                               q.base = b + 1; // 增加base值
                               if (n < -1) // 队列大于一个任务,那么其他线程赶紧起来干活
                                   signalWork(ws, q);
                               return t; // 返回获取的任务
                           }
                       }
                       // oldSum未改变之前,才能判断w的扫描状态,如果扫描状态小于0,代表INACITVE,此时需要尝试唤醒空闲线程进行扫描工作
                       else if (oldSum == 0 && 
                                w.scanState < 0)
                           // c最新的ctl值,ws[m & (int)c]栈顶的索引下标,AC_UNIT 用于计算活跃线程数
                           tryRelease(c = ctl, ws[m & (int)c], AC_UNIT);
                   }
                   // 任务不存在,那么判断,如果此时扫描状态处于INACTIVE的话,那么需要重新获取扫描状态,可能别的线程已经将其置为扫描状态
                   if (ss < 0)          
                       ss = w.scanState;
                   // 执行到这里,那么只可能是因为线程竞争导致的,所以为了减少竞争,那么重新计算随机数,转移获取任务的wq,复位origin,oldSum、checkSum 方便计算轮回
                   r ^= r << 1; r ^= r >>> 3; r ^= r << 10;
                   origin = k = r & m;      
                   oldSum = checkSum = 0;
                   continue;
               }
               checkSum += b; // 通过base数值来进行校验和计算
           }
           // 扫描wqs正好经历过一个周期
           if ((k = (k + 1) & m) == origin) {  
               // 工作线程处于活跃状态,或者状态没有改变,注意:这里进行了ss的状态更新 ss = w.scanState
               if ((ss >= 0 || (ss == (ss = w.scanState))) &&
                   // 旧的oldSum 和 新的 checkSum 比较,同时更新oldSum
                   oldSum == (oldSum = checkSum)) {
                   // 总结: stable 稳定态: 扫描状态不变 且 没有线程操作队列
                   // 工作线程切换为 INACTIVE且队列稳定,所以退出即可
                   if (ss < 0 || w.qlock < 0) 
                       break;
                   int ns = ss | INACTIVE;  // 将扫描状态设置为INACTIVE
                   long nc = ((SP_MASK & ns) |
                              (UC_MASK & ((c = ctl) - AC_UNIT))); // 活跃线程数减1
                   //CTL低32位就是空闲线程栈的栈顶,workqueue的stackPred就是栈中的空闲线程
                   w.stackPred = (int)c; // 之前栈顶空闲线程的索引下标+版本号 
                   // 优化到了极致。由于这里是volatile,进行直接赋值将会导致StoreStore和StoreLoad屏障,所以用unsafe类来普通变量赋值,减少性能损耗,而后面的CAS操作后,自然能够保证这里的scanState语义。
                   U.putInt(w, QSCANSTATE, ns);
                   // CAS 替换ctl值
                   if (U.compareAndSwapLong(this, CTL, c, nc))
                       // 这里又是一个优化点,因为CTL替换成功,必然scanState写成功,那么局部变量直接更新为最新值,而不用再去读scanState变量
                       ss = ns;
                   else
                       // 如果失败了,那么回退到原来的状态,因为CTL没有改变,也即active count没有减1成功,自然scanState需要回退。
                       w.scanState = ss;     
               }
               checkSum = 0;
           }
       }
   }
   return null;
}

扫描全局 workQueues 数组中每个队列中的任务数组 array,找到任务就返回任务,否则返回 null

  • runTask(…)
// 执行WorkQueue中执行scan获取到的FJT
final void runTask(ForkJoinTask<?> task) {
   // 日常判空
   if (task != null) { 
       // 标记当前wq的工作线程处于执行获取到的任务状态。即标记为偶数。取scanState的高31位。int SCANNING = 1
       scanState &= ~SCANNING; 
       // task是不是当前线程从队列里面获取的(scan),也即将task设置为currentSteal。这里先不要了解FJT的内容,只需要知道运行了,怎么运行的。不需要了解怎么去实现FJT等等,后面再说。
       (currentSteal = task).doExec();
       // 执行完毕之后释放currentSteal引用。为什么这里这么写?store buffer -> StoreLoad -> volatile语义?写变量时,StoreStore,StoreLoad。那么这里为了保证写入顺序-> putOrderedObject 避免了StoreLoad屏障对性能的损耗。
       U.putOrderedObject(this, QCURRENTSTEAL, null); 
       // 直接翻译:执行本地任务。为何执行本地任务?考虑一个问题:谁能往当前线程的工作队列里放任务?当前线程在执行FJT时往自己队列里放了任务,也只有当前线程才能往array任务数组里放任务。
       execLocalTasks();
       ForkJoinWorkerThread thread = owner;
       // nsteals代表了当前线程总的偷取的任务数量。由于符号限制,所以检查是否发生符号溢出
       if (++nsteals < 0) 
           // 当前线程32位计数值达到饱和,那么将其加到FJP的全局变量的64位计数器中,并且清零计数值 nsteals
           transferStealCount(pool);
       // 任务执行完成,恢复扫描状态
       scanState |= SCANNING;
       if (thread != null)
           thread.afterTopLevelExec(); // 任务执行完的钩子函数
   }
}
// 执行本地任务
final void execLocalTasks() {
   int b = base, m, s;
   // 当前工作线程的任务数组
   ForkJoinTask<?>[] a = array;
   if (b - (s = top - 1) <= 0 && // base 和 top 指针距离至少是1,表示至少有一个任务可拿
       a != null && // 任务数组不为空
       (m = a.length - 1) >= 0) { // 任务数组有任务
       // 取任务的模式
       if ((config & FIFO_QUEUE) == 0) { // 从 top 拿任务
           for (ForkJoinTask<?> t;;) {
               if ((t = (ForkJoinTask<?>)U.getAndSetObject
                    (a, ((m & s) << ASHIFT) + ABASE, null)) == null)
                   break;
               U.putOrderedInt(this, QTOP, s);
               t.doExec();
               if (base - (s = top - 1) > 0)
                   break;
           }
       }
       else // FIFO_QUEUE 从 base 拿任务
           pollAndExecAll();
   }
}

执行任务前修改 scanState,然后执行任务,执行完任务后恢复 scanState

  • awaitWork(…)
// FJP用于FJWT工作线程等待唤醒的方法
private boolean awaitWork(WorkQueue w, int r) {
   // 线程池正在Terminate
   if (w == null || w.qlock < 0)         
       return false; // 返回false 直接退出runWorker内部循环,也即退出FJWT
   // 取当前工作线程压入空闲栈中的前一个工作线程版本号+下标(32位切割为:高16 + 低16)赋值于pred,SPINS代表自旋次数为0
   for (int pred = w.stackPred, spins = SPINS, ss;;) {
       // 当前工作线程状态已经被修改为ACTIVE状态,那么赶紧干活去
       if ((ss = w.scanState) >= 0)
           break;
       else if (spins > 0) { // 没有达到自旋次数阈值 spins 自旋次数
           r ^= r << 6; r ^= r >>> 21; r ^= r << 7;
           if (r >= 0 && --spins == 0) {     // randomize spins
               WorkQueue v; WorkQueue[] ws; int s, j; AtomicLong sc;
               if (pred != 0 && (ws = workQueues) != null &&
                   (j = pred & SMASK) < ws.length &&
                   (v = ws[j]) != null &&    // see if pred parking
                   (v.parker == null || v.scanState >= 0))
                   spins = SPINS;        // continue spinning
           }
       }
       // 自旋之后再次检测下线程池状态
       else if (w.qlock < 0)           
           return false;
       // 如果当前FJWT工作线程没有发生中断,那么尝试睡眠,否则清除中断标志位后继续scan扫描任务,干活去
       else if (!Thread.interrupted()) {
           long c, prevctl, parkTime, deadline;
           // 之前我们以并行度64为例 AC(高32位的高16位) 1111 1111 1100 0000 64并行度:0000 0000 0100 0000
           // AC_SHIFT = 48 符号右移。获取高16位的值:活跃线程数
           // 取低16位config的值:在构造函数中设置的并行度(这里是64)SMASK = 0xffff
           int ac = (int)((c = ctl) >> AC_SHIFT) + (config & SMASK);
           // 总结:用64位的ctl的高32位的高16位与设置的并行度相加可以得到ac,也即活跃线程数
           // 此时 ac = 0 。那么代表了活跃线程数为0。活跃线程数为0之后,我需要看看FJP有没有设置SHUTDOWN或者STOP。此时需要调用tryTerminate看看自己是不是最后一个线程,然后做清理和进一步的操作
           if ((ac <= 0 && tryTerminate(false, false)) ||
               // 线程池状态处于STOP停止态,所以停止执行
               (runState & STOP) != 0)      
               return false;
           // 看看当前线程是不是最后一个空闲线程
           if (ac <= 0 && ss == (int)c) {    
               // 为什么这里要加1?我当前线程结束了吗?在我FJP线程代码没有执行完毕之前我还是属于FJP的,所以还是属于活跃线程。这里TC都还没改呢?
               prevctl = (UC_MASK & (c + AC_UNIT)) | 
                   // 因为当前线程要释放资源,不属于FJP了,所以栈顶还原到之前的索引下标
                   (SP_MASK & pred);
               // 取CTL中的总线程数:活跃线程数(AC)+非活跃线程数(空闲线程数)
               int t = (short)(c >>> TC_SHIFT); 
               // 保证至少有三个空闲线程即可。由于当前线程池处于静默状态,如果持有太多空闲线程将会浪费系统资源,那么何不如把线程释放掉,而又需要保持线程池的活性,即有任务也能不创建线程执行,那么这里设置阈值为3个空闲线程数。这里写法不规范,理论上来说这是可以调节的,设置为全局变量比较合适
               if (t > 2 && 
                   // 如果这里t>2,那么表明有足够多的空闲线程,那么我需要将CTL还原到 + 1 ac 和 之前栈顶的线程索引
                   U.compareAndSwapLong(this, CTL, c, prevctl))
                   return false;         
               parkTime = IDLE_TIMEOUT * ((t >= 0) ? 1 : 1 - t);
               deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP;
           }
           else
               prevctl = parkTime = deadline = 0L;
           Thread wt = Thread.currentThread();
           // 模拟 LockSupport。其实就是设置阻塞对象,表示当前线程阻塞在哪个对象上
           U.putObject(wt, PARKBLOCKER, this); 
           // 设置当前workqueue阻塞在哪个线程上
           w.parker = wt;
           // 在执行阻塞之前,再次检测状态位:当前worker必须处于空闲状态且ctl没有被改变过
           if (w.scanState < 0 && ctl == c)   
               U.park(false, parkTime);
           // 被唤醒后,清空标识字段
           U.putOrderedObject(w, QPARKER, null);
           U.putObject(wt, PARKBLOCKER, null);
           // 被唤醒后,扫描状态被设置>0,说明处于活跃状态,直接break
           if (w.scanState >= 0)
               break;
           if (parkTime != 0L &&  // 设置了阻塞时间
               ctl == c &&  // ctl没有改变过
               deadline - System.nanoTime() <= 0L && // 超时了
               U.compareAndSwapLong(this, CTL, c, prevctl)) // 收缩线程池
               return false;          
       }
   }
   return true;
}

自旋等待被唤醒

7. 线程池关闭
  • shutdown()
public void shutdown() {
   // 检查权限
   checkPermission();
   tryTerminate(false, true);
}
  • tryTerminate(…)
// 实际关闭方法。enable指明如果线程池状态处于活跃状态时,能不能修改状态。
private boolean tryTerminate(boolean now, boolean enable) {
   int rs;
   // 当前线程池是common公用线程池不允许被关闭
   if (this == common)           
       return false;
   if ((rs = runState) >= 0) { // 线程池处于活跃状态
       if (!enable)   // 如果enable为false,直接退出
           return false;
       rs = lockRunState();  // 进入 SHUTDOWN 阶段
       // 去除RSLOCK位,并加上SHUTDOWN标志位
       unlockRunState(rs, (rs & ~RSLOCK) | SHUTDOWN);
   }
   // 此时标志位SHUTDOWN已经设置,那么通过之前的描述得知,此时线程池不会再接收新的任务
   // 此时,线程池状态处于SHUTDOWN状态,没有设置STOP标志位
   if ((rs & STOP) == 0) {
       // 如果没有设置立即无条件结束线程池,那么需要检测一下静默状态,看看是否所有线程都是空闲的
       if (!now) {        
           // 重复检测,直到FJP稳定
           for (long oldSum = 0L;;) {   
               WorkQueue[] ws; WorkQueue w; int m, b; long c;
               // 校验和变量默认等于最新的ctl值
               long checkSum = ctl;
               // 计算ac值, ac大于0,说明仍然有活跃线程,直接返回即可
               if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
                   return false;   
               // wqs都没有创建,那就直接结束呗
               if ((ws = workQueues) == null || (m = ws.length - 1) <= 0)
                   break;         
               // 遍历所有队列。包括:外部提交队列、内部工作队列(窃取队列)
               for (int i = 0; i <= m; ++i) {
                   // 队列存在
                   if ((w = ws[i]) != null) {
                       if ((b = w.base) != w.top || // 队列中有任务
                           w.scanState >= 0 ||  // 处于工作状态
                           w.currentSteal != null) {// 正在执行任务
                           // 唤醒INACTIVE线程,尽快完成工作
                           tryRelease(c = ctl, ws[m & (int)c], AC_UNIT);
                           return false;   // 当前FJP还有任务在执行,当前线程先返回
                       }
                       // 计算校验和
                       checkSum += b;
                       // 取wqs偶数位,设置qlock=-1。禁用外部队列
                       if ((i & 1) == 0)
                           w.qlock = -1;   
                   }
               }
               // 检测FJP是否处于稳定状态,也即没有任务出入,遍历两次
               if (oldSum == (oldSum = checkSum))
                   break;
           }
       }
       // 当前线程,发现队列处于稳定状态,且已经没有任何任务可执行。直接将状态变为STOP
       if ((runState & STOP) == 0) {
           rs = lockRunState();       // enter STOP phase
           unlockRunState(rs, (rs & ~RSLOCK) | STOP);
       }
   }
   // 此时进入STOP阶段,那么开始帮忙转变状态为terminate
   int pass = 0;               // 通过三个步骤来逐步帮助terminate线程池
   for (long oldSum = 0L;;) {        // 循环直到完成或者稳定
       WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt; int m;
       long checkSum = ctl;
       // 这是不是最终状态
       // 总线程数为0,也即FJP中没有活动和非活动线程,也即所有的线程都没了
       if ((short)(checkSum >>> TC_SHIFT) + (config & SMASK) <= 0 ||
           // 队列不存在
           (ws = workQueues) == null || (m = ws.length - 1) <= 0) {
           // 当前线程直接转变状态即可
           if ((runState & TERMINATED) == 0) {
               rs = lockRunState();     // done
               // 将状态改为最终状态:TERMINATED
               unlockRunState(rs, (rs & ~RSLOCK) | TERMINATED);
               // 从这里立刻得知:awaitTermination,等待线程池终结是通过this对象进行阻塞
               synchronized (this) { notifyAll(); } // for awaitTermination
           }
           break;
       }
       // 有线程且队列存在。那么,遍历每一个wq。只处理wq存在的队列。STOP状态含义:工作线程停止工作不管队列中是否还有任务
       for (int i = 0; i <= m; ++i) {
           if ((w = ws[i]) != null) {
               // 计算校验和,判定队列处于稳定状态,不能放也不能取
               checkSum += w.base;
               // 直接禁用掉所有的队列wq。此时,不管队列里面是否有任务,都不在执行,详情请看scan方法
               w.qlock = -1;   
               // pass为0时,为第一次进入,所以不会执行下面的语句
               if (pass > 0) {
                   w.cancelAll();      // 将队列中剩余的任务都清空
                   if (pass > 1 && (wt = w.owner) != null) { // 只有内部工作队列
                       // 如果队列中线程还处于运行状态,那么将其中断
                       if (!wt.isInterrupted()) {
                           try {       // unblock join
                               wt.interrupt();
                           } catch (Throwable ignore) {
                           }
                       }
                       // 如果线程处于INACTIVE状态,那么将其唤醒
                       if (w.scanState < 0)
                           U.unpark(wt);   // wake up
                   }
               }
           }
       }
       // checksum由上面的w.base来决定,如果仍有队列不为空,这时checksum会改变,导致处于不稳定状态,那么重置pass继续循环
       if (checkSum != oldSum) {       // unstable
           oldSum = checkSum;
           pass = 0;
       }
       // 到达这里的判断,也即所有的队列都处于稳定状态
       // 如果当前线程已经经过三次循环,还没有满足第一个判断句,也即总线程数为0,那么看看循环次数是否大于wqs的长度,如果是,那么直接退出,否则继续
       else if (pass > 3 && pass > m)    
           break;
       // 尝试将所有在等待栈中的线程全部唤醒
       else if (++pass > 1) {        
           long c; int j = 0, sp;      
           while (j++ <= m && (sp = (int)(c = ctl)) != 0)
               tryRelease(c, ws[sp & m], AC_UNIT);
       }
   }
   return true;
}
  • awaitTermination(…)
// 等待FJP线程状态变为TERMINATED
public boolean awaitTermination(long timeout, TimeUnit unit)
   throws InterruptedException {
   // 响应中断
   if (Thread.interrupted())
       throw new InterruptedException();
   // common线程池是不能够被关闭的,所以直接调用awaitQuiescence,然后返回false
   if (this == common) {
       awaitQuiescence(timeout, unit);
       return false;
   }
   long nanos = unit.toNanos(timeout);
   // 已经终结了,那么直接返回true
   if (isTerminated())
       return true;
   // 超时了不等待,直接返回false
   if (nanos <= 0L)
       return false;
   // 计算等待的截止时间
   long deadline = System.nanoTime() + nanos;
   // 阻塞在this FJP对象的监视器锁中,直到状态变为TERMINATED然后被唤醒
   synchronized (this) {
       for (;;) {
           if (isTerminated()) // 要么关闭
               return true;
           if (nanos <= 0L) // 要么超时
               return false;
           long millis = TimeUnit.NANOSECONDS.toMillis(nanos);
           wait(millis > 0L ? millis : 1L); // 等待即可
           nanos = deadline - System.nanoTime();
       }
   }
}
8. 加锁、等待锁、释放锁
  • lockRunState()
// CAS上把锁
private int lockRunState() {
   int rs;
   return ((((rs = runState) & RSLOCK) != 0 ||
            !U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)) ?
           awaitRunStateLock() : rs);
}
  • awaitRunstateLock()
// 等待获取锁
private int awaitRunStateLock() {
   Object lock;
   boolean wasInterrupted = false;
   for (int spins = SPINS, r = 0, rs, ns;;) {
       // 锁已经被释放,那么可以去CAS竞争锁
       if (((rs = runState) & RSLOCK) == 0) {
           if (U.compareAndSwapInt(this, RUNSTATE, rs, ns = rs | RSLOCK)) {
               if (wasInterrupted) {
                   try {
                       Thread.currentThread().interrupt();
                   } catch (SecurityException ignore) {
                   }
               }
               return ns;
           }
       }
       else if (r == 0) // 初始化随机数
           r = ThreadLocalRandom.nextSecondarySeed();
       else if (spins > 0) { // 随机,减少自旋次数
           r ^= r << 6; r ^= r >>> 21; r ^= r << 7; // 异或随机数
           if (r >= 0)
               --spins;
       }
       else if ((rs & STARTED) == 0 || (lock = stealCounter) == null)
           Thread.yield();  // 由于当前rs的STARTED状态位为0,代表了,当前FJP没有在运行了,那么没有必要再去睡眠了,因为这个状态维持时间会非常短
       // 光是睡眠不行,需要有人唤醒,所以这里必须置位 RSIGNAL 唤醒位,提示另外的线程需要唤醒它
       else if (U.compareAndSwapInt(this, RUNSTATE, rs, rs | RSIGNAL)) {
           synchronized (lock) {
               if ((runState & RSIGNAL) != 0) {
                   try {
                       lock.wait();
                   } catch (InterruptedException ie) {
                       if (!(Thread.currentThread() instanceof
                             ForkJoinWorkerThread))
                           wasInterrupted = true;
                   }
               }
               else
                   lock.notifyAll();
           }
       }
   }
}
  • unlockRunState(…)
// 解锁
private void unlockRunState(int oldRunState, int newRunState) {
   if (!U.compareAndSwapInt(this, RUNSTATE, oldRunState, newRunState)) {
       Object lock = stealCounter;
       runState = newRunState;       // clears RSIGNAL bit
       if (lock != null)
           synchronized (lock) { lock.notifyAll(); }
   }
}
9. TODO 🦅
  • awaitJoin(…)
final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
   int s = 0;
   if (task != null && w != null) {
       ForkJoinTask<?> prevJoin = w.currentJoin;
       U.putOrderedObject(w, QCURRENTJOIN, task);
       CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
           (CountedCompleter<?>)task : null;
       for (;;) {
           if ((s = task.status) < 0)
               break;
           if (cc != null)
               helpComplete(w, cc, 0);
           else if (w.base == w.top || w.tryRemoveAndExec(task))
               helpStealer(w, task);
           if ((s = task.status) < 0)
               break;
           long ms, ns;
           if (deadline == 0L)
               ms = 0L;
           else if ((ns = deadline - System.nanoTime()) <= 0L)
               break;
           else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
               ms = 1L;
           if (tryCompensate(w)) {
               task.internalWait(ms);
               U.getAndAddLong(this, CTL, AC_UNIT);
           }
       }
       U.putOrderedObject(w, QCURRENTJOIN, prevJoin);
   }
   return s;
}
  • helpStealer(…)
private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
   WorkQueue[] ws = workQueues;
   int oldSum = 0, checkSum, m;
   if (ws != null && (m = ws.length - 1) >= 0 && w != null &&
       task != null) {
       do {                    // restart point
           checkSum = 0;             // for stability check
           ForkJoinTask<?> subtask;
           WorkQueue j = w, v;          // v is subtask stealer
           descent: for (subtask = task; subtask.status >= 0; ) {
               for (int h = j.hint | 1, k = 0, i; ; k += 2) {
                   if (k > m)           // can't find stealer
                       break descent;
                   if ((v = ws[i = (h + k) & m]) != null) {
                       if (v.currentSteal == subtask) {
                           j.hint = i;
                           break;
                       }
                       checkSum += v.base;
                   }
               }
               for (;;) {             // help v or descend
                   ForkJoinTask<?>[] a; int b;
                   checkSum += (b = v.base);
                   ForkJoinTask<?> next = v.currentJoin;
                   if (subtask.status < 0 || j.currentJoin != subtask ||
                       v.currentSteal != subtask) // stale
                       break descent;
                   if (b - v.top >= 0 || (a = v.array) == null) {
                       if ((subtask = next) == null)
                           break descent;
                       j = v;
                       break;
                   }
                   int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
                   ForkJoinTask<?> t = ((ForkJoinTask<?>)
                                        U.getObjectVolatile(a, i));
                   if (v.base == b) {
                       if (t == null)       // stale
                           break descent;
                       if (U.compareAndSwapObject(a, i, t, null)) {
                           v.base = b + 1;
                           ForkJoinTask<?> ps = w.currentSteal;
                           int top = w.top;
                           do {
                               U.putOrderedObject(w, QCURRENTSTEAL, t);
                               t.doExec();    // clear local tasks too
                           } while (task.status >= 0 &&
                                    w.top != top &&
                                    (t = w.pop()) != null);
                           U.putOrderedObject(w, QCURRENTSTEAL, ps);
                           if (w.base != w.top)
                               return;      // can't further help
                       }
                   }
               }
           }
       } while (task.status >= 0 && oldSum != (oldSum = checkSum));
   }
}
  • helpComplete(…)
final int helpComplete(WorkQueue w, CountedCompleter<?> task,
                      int maxTasks) {
   WorkQueue[] ws; int s = 0, m;
   if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 &&
       task != null && w != null) {
       int mode = w.config;         // for popCC
       int r = w.hint ^ w.top;       // arbitrary seed for origin
       int origin = r & m;         // first queue to scan
       int h = 1;              // 1:ran, >1:contended, <0:hash
       for (int k = origin, oldSum = 0, checkSum = 0;;) {
           CountedCompleter<?> p; WorkQueue q;
           if ((s = task.status) < 0)
               break;
           if (h == 1 && (p = w.popCC(task, mode)) != null) {
               p.doExec();         // run local task
               if (maxTasks != 0 && --maxTasks == 0)
                   break;
               origin = k;         // reset
               oldSum = checkSum = 0;
           }
           else {              // poll other queues
               if ((q = ws[k]) == null)
                   h = 0;
               else if ((h = q.pollAndExecCC(task)) < 0)
                   checkSum += h;
               if (h > 0) {
                   if (h == 1 && maxTasks != 0 && --maxTasks == 0)
                       break;
                   r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
                   origin = k = r & m;   // move and restart
                   oldSum = checkSum = 0;
               }
               else if ((k = (k + 1) & m) == origin) {
                   if (oldSum == (oldSum = checkSum))
                       break;
                   checkSum = 0;
               }
           }
       }
   }
   return s;
}
  • tryCompensate(…)
private boolean tryCompensate(WorkQueue w) {
   boolean canBlock;
   WorkQueue[] ws; long c; int m, pc, sp;
   if (w == null || w.qlock < 0 ||      // caller terminating
       (ws = workQueues) == null || (m = ws.length - 1) <= 0 ||
       (pc = config & SMASK) == 0)      // parallelism disabled
       canBlock = false;
   else if ((sp = (int)(c = ctl)) != 0)   // release idle worker
       canBlock = tryRelease(c, ws[sp & m], 0L);
   else {
       int ac = (int)(c >> AC_SHIFT) + pc;
       int tc = (short)(c >> TC_SHIFT) + pc;
       int nbusy = 0;            // validate saturation
       for (int i = 0; i <= m; ++i) {    // two passes of odd indices
           WorkQueue v;
           if ((v = ws[((i << 1) | 1) & m]) != null) {
               if ((v.scanState & SCANNING) != 0)
                   break;
               ++nbusy;
           }
       }
       if (nbusy != (tc << 1) || ctl != c)
           canBlock = false;         // unstable or stale
       else if (tc >= pc && ac > 1 && w.isEmpty()) {
           long nc = ((AC_MASK & (c - AC_UNIT)) |
                      (~AC_MASK & c));    // uncompensated
           canBlock = U.compareAndSwapLong(this, CTL, c, nc);
       }
       else if (tc >= MAX_CAP ||
                (this == common && tc >= pc + commonMaxSpares))
           throw new RejectedExecutionException(
           "Thread limit exceeded replacing blocked worker");
       else {                // similar to tryAddWorker
           boolean add = false; int rs;   // CAS within lock
           long nc = ((AC_MASK & c) |
                      (TC_MASK & (c + TC_UNIT)));
           if (((rs = lockRunState()) & STOP) == 0)
               add = U.compareAndSwapLong(this, CTL, c, nc);
           unlockRunState(rs, rs & ~RSLOCK);
           canBlock = add && createWorker(); // throws on exception
       }
   }
   return canBlock;
}
  • tryRelease(…)
private boolean tryRelease(long c, WorkQueue v, long inc) {
   int sp = (int)c, vs = (sp + SS_SEQ) & ~INACTIVE; Thread p;
   if (v != null && v.scanState == sp) {     // v is at top of stack
       long nc = (UC_MASK & (c + inc)) | (SP_MASK & v.stackPred);
       if (U.compareAndSwapLong(this, CTL, c, nc)) {
           v.scanState = vs;
           if ((p = v.parker) != null)
               U.unpark(p);
           return true;
       }
   }
   return false;
}
3、ForkJoinTask
1. doExec()
// FJT的方法,由FJP的工作线程调用
volatile int status; // 当前FJT的运行状态
static final int DONE_MASK  = 0xf0000000; // 取完成位的掩码
static final int NORMAL   = 0xf0000000; // 正常状态
static final int CANCELLED  = 0xc0000000; // 被取消了
static final int EXCEPTIONAL = 0x80000000; // 发生了异常
static final int SIGNAL   = 0x00010000; // 需要唤醒
static final int SMASK    = 0x0000ffff; // 取低16位的掩码
final int doExec() {
    int s; boolean completed;
    // 默认状态就是0,新建状态
    if ((s = status) >= 0) {
        try {
            // 子类需要实现该方法完成调用
            completed = exec();
        } catch (Throwable rex) {
            return setExceptionalCompletion(rex);
        }
        // 如果执行完成,那么设置状态为NORMAL,表示正常完成
        if (completed)
            s = setCompletion(NORMAL);
    }
    return s;
}
2. fork()
// FJT的fork方法,将任务放入FJP中执行
public final ForkJoinTask<V> fork() {
    Thread t;
    if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
        // 如果是内部工作线程,那么直接将其放入自己的队列中 push方法
        ((ForkJoinWorkerThread)t).workQueue.push(this);
    else
        // 外部线程就调用externalPush,其实就是调用Common线程池来执行
        ForkJoinPool.common.externalPush(this);
    return this;
}
// FJP用于内部工作线程往自己的队列存放任务
final void push(ForkJoinTask<?> task) {
    ForkJoinTask<?>[] a; ForkJoinPool p;
    int b = base, s = top, n;
    if ((a = array) != null) {  // ignore if queue removed
        int m = a.length - 1;   // fenced write for task visibility
        // 获取top变量的偏移量,然后放入task对象
        U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
        // 对top值加1
        U.putOrderedInt(this, QTOP, s + 1);
        // 使用putOrdered保证了STORESTORE语义
        if ((n = s - b) <= 1) { // n为top引用和base引用中间的有效任务数
            // 为何这里要小于等于1才唤醒等待线程,只要这里大于1了,那么必然已经都唤醒了
            if ((p = pool) != null)
                p.signalWork(p.workQueues, this);
        }
        else if (n >= m) // 满了扩容
            growArray();
    }
}
3. join()
// 等待当前任务执行完完成
public final V join() {
    int s;
    // 等待过程中发现任务执行出了异常,然后调用reportException抛出异常
    if ((s = doJoin() & DONE_MASK) != NORMAL)
        reportException(s);
    // 正常完成就拿结果即可
    return getRawResult();
}
// 真正等待的方法
private int doJoin() {
    int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
    return (s = status) < 0 ? s :
    ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
        (w = (wt = (ForkJoinWorkerThread)t).workQueue).
        tryUnpush(this) && (s = doExec()) < 0 ? s :
    wt.pool.awaitJoin(w, this, 0L) :
    externalAwaitDone();
}
(p);
            return true;
        }
    }
    return false;
}
3、ForkJoinTask
1. doExec()
// FJT的方法,由FJP的工作线程调用
volatile int status; // 当前FJT的运行状态
static final int DONE_MASK  = 0xf0000000; // 取完成位的掩码
static final int NORMAL   = 0xf0000000; // 正常状态
static final int CANCELLED  = 0xc0000000; // 被取消了
static final int EXCEPTIONAL = 0x80000000; // 发生了异常
static final int SIGNAL   = 0x00010000; // 需要唤醒
static final int SMASK    = 0x0000ffff; // 取低16位的掩码
final int doExec() {
    int s; boolean completed;
    // 默认状态就是0,新建状态
    if ((s = status) >= 0) {
        try {
            // 子类需要实现该方法完成调用
            completed = exec();
        } catch (Throwable rex) {
            return setExceptionalCompletion(rex);
        }
        // 如果执行完成,那么设置状态为NORMAL,表示正常完成
        if (completed)
            s = setCompletion(NORMAL);
    }
    return s;
}
2. fork()
// FJT的fork方法,将任务放入FJP中执行
public final ForkJoinTask<V> fork() {
    Thread t;
    if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
        // 如果是内部工作线程,那么直接将其放入自己的队列中 push方法
        ((ForkJoinWorkerThread)t).workQueue.push(this);
    else
        // 外部线程就调用externalPush,其实就是调用Common线程池来执行
        ForkJoinPool.common.externalPush(this);
    return this;
}
// FJP用于内部工作线程往自己的队列存放任务
final void push(ForkJoinTask<?> task) {
    ForkJoinTask<?>[] a; ForkJoinPool p;
    int b = base, s = top, n;
    if ((a = array) != null) {  // ignore if queue removed
        int m = a.length - 1;   // fenced write for task visibility
        // 获取top变量的偏移量,然后放入task对象
        U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
        // 对top值加1
        U.putOrderedInt(this, QTOP, s + 1);
        // 使用putOrdered保证了STORESTORE语义
        if ((n = s - b) <= 1) { // n为top引用和base引用中间的有效任务数
            // 为何这里要小于等于1才唤醒等待线程,只要这里大于1了,那么必然已经都唤醒了
            if ((p = pool) != null)
                p.signalWork(p.workQueues, this);
        }
        else if (n >= m) // 满了扩容
            growArray();
    }
}
3. join()
// 等待当前任务执行完完成
public final V join() {
    int s;
    // 等待过程中发现任务执行出了异常,然后调用reportException抛出异常
    if ((s = doJoin() & DONE_MASK) != NORMAL)
        reportException(s);
    // 正常完成就拿结果即可
    return getRawResult();
}
// 真正等待的方法
private int doJoin() {
    int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
    return (s = status) < 0 ? s :
    ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
        (w = (wt = (ForkJoinWorkerThread)t).workQueue).
        tryUnpush(this) && (s = doExec()) < 0 ? s :
    wt.pool.awaitJoin(w, this, 0L) :
    externalAwaitDone();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值