线程池 ThreadPoolExecutor 源码解析

阅读须知

  • JDK版本:1.8
  • 文章中使用/* */注释的方法会做深入分析

正文

构造方法:
ThreadPoolExecutor:

public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
    null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

构造方法参数解释:

  • corePoolSize:向线程池中提交任务时,线程池会创建一个新线程来执行任务,直到当前线程数等于 corePoolSize,这时后面再次提交的任务会被保存到阻塞队列中,等待被执行。如果执行了线程池的 prestartAllCoreThreads 方法,线程池会提前创建并启动所有核心线程
  • maximumPoolSize:线程池线程数量的最大上限,如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于 maximumPoolSize
  • keepAliveTime:线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间,默认情况下,该参数只在线程数大于 corePoolSize 时才有用
  • unit:是 keepAliveTime 的时间单位
  • workQueue:任务存储的队列,用来保存等待被执行的任务的阻塞队列,在 JDK 中提供了如下阻塞队列:
    • ArrayBlockingQueue:基于数组结构的有界阻塞队列,按 FIFO 排序任务
    • LinkedBlockingQuene:基于链表结构的阻塞队列,按 FIFO 排序任务,吞吐量通常要高于ArrayBlockingQuene
    • SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 LinkedBlockingQuene
    • priorityBlockingQuene:具有优先级的无界阻塞队列
  • threadFactory:创建线程的工厂,默认为 Executors.DefaultThreadFactory,里面定义了线程计数,并且给生产的线程命名(pool-线程池号-thread-线程号),可以自定义,实现 ThreadFactory 重写 newThread 方法
  • handler:饱和策略,可以自定义,实现 RejectedExecutionHandler 重写 rejectedExecution 方法
    • AbortPolicy:默认饱和策略,直接抛出一个 RejectedExecutionException 异常,让调用者自己处理
    • DiscardPolicy:后续的任务都抛弃掉
    • DiscardOldestPolicy:会将等待队列里最旧的任务踢走,让新任务得以执行
    • CallerRunsPolicy:它既不抛弃新任务,也不抛弃旧任务,而是直接在当前线程运行这个任务,当前线程一般就是主线程,主线程运行任务,有可能会阻塞,推荐少用

向线程池提交任务时会用到 execute 方法:
ThreadPoolExecutor:

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        /* 如果当前线程数量小于 corePoolSize,添加 worker 执行任务 */
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 判断是否在 RUNNING 状态并且可以成功将任务添加到队列中
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            // 二次检查运行状态,如果不是 RUNNING 并且可以成功从队列中移除,则拒绝任务走饱和策略
            reject(command);
        else if (workerCountOf(recheck) == 0)
            // 如果线程池中已经没有线程,则添加一个线程
            addWorker(null, false);
    }
    // 如果添加队列失败,尝试增加 worker 来执行任务
    else if (!addWorker(command, false))
        // 如果上面失败,则说明线程已经超过 maximumPoolSize 或者已关闭,则拒绝任务走饱和策略
        reject(command);
}

这里翻译一下方法中给出的注释:

分三步进行:

  1. 如果少于 corePoolSize 个线程正在运行,尝试使用给定command作为第一个任务启动一个新线程,调用 addWorker 方法时以原子方式检查 runState 和 workerCount ,返回 false 防止在不应该增加时增加线程。
  2. 如果任务可以成功入队,仍然需要二次检查是否应该添加一个线程(因为线程池在第一次检查之后可能已经死掉了)或者自进入此方法后线程池关闭了。所以需要重新检查状态,如果有必要的话回滚队列(将本次新提交的任务从队列中移除),否则就添加一个新的线程。
  3. 如果任务不能入队,则尝试添加一个新线程。如果添加新线程失败,则证明线程池已关闭或已饱和,因此拒绝任务。

下图可以很清晰的表示这个过程:
这里写图片描述
方法里获取线程池的运行状态和线程数量都和一个叫做 ctl 的变量有关,这里翻译一下变量的注释:

主要的线程池控制状态,ctl 是一个包含两个概念字段的原子整数

  1. workerCount:表明线程的有效数量
  2. runState:表明是否运行,关闭等
    为了将它们打包到一个 int 中,我们将 workerCount 限制为(2 ^ 29)-1(约5亿)个线程,而不是(2 ^ 31)-1(20亿),如果未来这变成了一个问题,则可以将变量可以改为 AtomicLong ,并调整下面的 shift / mask 常量。但在问题出现之前,使用 int 可以更快更简单。
    workerCount 是已经被允许启动并且不被允许停止的 worker 的数量。该值可能与活动线程的实际数量暂时不同,例如,当 ThreadFactory 在被询问时未能创建线程,以及退出线程在终止之前仍在执行时。用户可见池大小作为 worker 组的当前大小。
    runState 提供了主要的生命周期控制,取值为:
  3. RUNNING:接受新任务并处理排队的任务
  4. SHUTDOWN:不接受新任务,但处理排队的任务
  5. STOP:不接受新任务,不处理排队的任务,并中断正在进行的任务
  6. TIDYING:所有任务都已终止,workerCount 为零,转换为状态 TIDYING 的线程将运行 terminate 钩子方法
  7. TERMINATED:terminate 已完成
    这些值之间的数字顺序很重要,可以进行有序的比较。runState 随着时间的推移单调增加,但不需要过每个状态。状态转换过程为:
  8. RUNNING -> SHUTDOWN:在调用 shutdown 时,可能会隐含在 finalize 中
  9. (RUNNING or SHUTDOWN) -> STOP:在调用 shutdownNow 时
  10. SHUTDOWN -> TIDYING:当队列和池都是空的时候
  11. STOP -> TIDYING:当池是空的时候
  12. TIDYING -> TERMINATED:当 terminate 钩子方法完成时

当状态达到 TERMINATED 时,在 awaitTermination 中等待的线程将返回。
检测从 SHUTDOWN 到 TIDYING 的转换并不像你想的那样直接,因为在 SHUTDOWN 状态期间非空队列可能变空,反之亦然,但是我们只能在看到它为空时看到 workerCount 是0(有时需要重新检查 - 见下文)。

这个注释对理解线程池的工作流程非常重要,这里看到 ctl 表示了两个变量,其中低29位表示线程池中线程数 workerCount,通过高3位表示线程池的运行状态 runState,代码中相关变量的声明和计算如下:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 29
private static final int COUNT_BITS = Integer.SIZE - 3;
// runState 存储在高位中
// 线程容量536870911
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
// 高三位111
private static final int RUNNING    = -1 << COUNT_BITS;
// 高三位000
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 高三位001
private static final int STOP       =  1 << COUNT_BITS;
// 高三位010
private static final int TIDYING    =  2 << COUNT_BITS;
// 高三位011
private static final int TERMINATED =  3 << COUNT_BITS;
// 打包和解包 ctl
private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

接下来是添加线程执行任务的过程:
ThreadPoolExecutor:

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        // 获取运行状态
        int rs = runStateOf(c);
        // 判断如果运行状态大于等于 SHUTDOWN,并且(在状态等于 SHUTDOWN 任务为 null 时检查队列是否为空),满足上述条件,则直接返回,不处理任何任务
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
                firstTask == null &&
                ! workQueue.isEmpty()))
            return false;
        for (;;) {
            // 获取线程池当期的线程数量
            int wc = workerCountOf(c);
            // 判断当前线程数量如果大于等于线程容量或者根据传入的 core 布尔值判断当前线程数量是否大于等于 corePoolSize 或 maximumPoolSize,满足上述条件,则直接返回,不处理任何任务
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // 尝试 CAS 递增 ctl 的 workerCount 字段
            if (compareAndIncrementWorkerCount(c))
                break retry;
            // 重新读取 ctl
            c = ctl.get();
            if (runStateOf(c) != rs)
                // 如果运行状态改变了,重新进入这个循环
                continue retry;
            // 否则由于 workerCount 更改 CAS 失败; 重试内部循环
        }
    }
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        /* 创建 worker */
        w = new Worker(firstTask);
        // 获取 worker 的线程
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                int rs = runStateOf(ctl.get());
                // 判断运行状态是否小于 SHUTDOWN 也就是 RUNNING 状态或者运行状态为 SHUTDOWN 并且提交的任务为 null
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    // 预先检查线程是否可以启动
                    if (t.isAlive())
                        throw new IllegalThreadStateException();
                    // 将 Worker 添加到线程池集合中,集合包含池中的所有工作线程,只有在持有 mainLock 时才能访问
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        // 设置此时线程池中的最大线程数量
                        largestPoolSize = s;
                    // 设置成功添加 worker 标记
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                // 如果成功添加 worker 则启动线程
                t.start();
                // 设置 worker 启动成功标记
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            /* 添加 worker 失败处理 */
            addWorkerFailed(w);
    }
    return workerStarted;
}

Worker 继承了 AQS(AbstractQueuedSynchronizer)并且实现了 Runnable:
ThreadPoolExecutor.Worker:

Worker(Runnable firstTask) {
    // 设置 AQS 状态,禁止中断,直到 runWorker
    setState(-1);
    this.firstTask = firstTask;
    // 线程工厂创建线程
    this.thread = getThreadFactory().newThread(this);
}

线程工厂默认为 Executors.DefaultThreadFactory,这里创建线程时传入了 this,也就是 Worker,Worker 实现了 Runnable,所以线程启动之后就会运行它的 run 方法:
ThreadPoolExecutor.Worker:

public void run() {
    /* 委托外部 runWorker 方法运行 */
    runWorker(this);
}

ThreadPoolExecutor:

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    // 允许中断
    w.unlock();
    // 标记线程是否突然终止
    boolean completedAbruptly = true;
    try {
        /* 如果当前任务不为 null,则运行当前任务,否则尝试获取任务执行 */
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // 如果线程池已停止,确保线程中断; 如果没有,确保线程不中断。这需要在第二种情况下进行重新检查,以便在清除中断时处理 shutdownNow 竞争
            if ((runStateAtLeast(ctl.get(), STOP) ||
                (Thread.interrupted() &&
                    runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                // 任务执行前置处理,默认空实现,留给子类扩展
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    // 执行提交的任务
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    // 任务执行后置处理,默认空实现,留给子类扩展
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                // 增加 worker 完成的任务数量
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        /* worker 退出处理 */
        processWorkerExit(w, completedAbruptly);
    }
}

ThreadPoolExecutor:

private Runnable getTask() {
    // 标记最后一次 poll 是否超时了
    boolean timedOut = false;
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // 判断是否运行状态大于等于 SHUTDOWN 并且运行状态大于等于 STOP 或者任务队列为空
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            // 循环 CAS 递减 ctl 的 workerCount 字段,直到成功
            decrementWorkerCount();
            return null;
        }
        int wc = workerCountOf(c);
        // 标记是否允许杀死 worker(判断是否允许核心线程超时,默认为 false 或者当前线程数量大于 corePoolSize)
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // CAS 递减 ctl 的 workerCount 字段
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        try {
            // 从队列中获取任务
            Runnable r = timed ?
            // 如果在 keepAliveTime 时间内,阻塞队列还是没有任务,则返回 null
            workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : 
            // 如果阻塞队列为空,当前线程会被挂起等待;当队列中有任务加入时,线程被唤醒, take 方法返回任务,并执行
            workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

getTask 就是循环不停的从队列中获取任务,在文章开始介绍的 keepAliveTime 参数,就是在这里生效的,这里说明一下这个过程:

  1. 当 timed 为 true 时,也就是允许核心线程超时或者当前线程数量大于 corePoolSize 时,这时会调用workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)进行任务的获取,如果在 keepAliveTime 时间内,阻塞队列还是没有任务,则返回null
  2. 返回 null 会将 timedOut 标记为 true,表示 poll 操作超时了
  3. 进入下一次循环,判断(当前线程数大于 maximumPoolSize 或者(timed 为 true 并且 timedOut 为 ture))并且(当前线程数大于1或者任务队列为空),这时会 CAS 递减 ctl 的 workerCount 字段,也就是减少线程的数量,并返回 null
  4. getTask 方法返回 null 后调用栈上层的 runWorker 方法的 while 条件就无法满足,这时会进入 processWorkerExit 方法进行 worker 退出处理,processWorkerExit 方法会移除 worker,来看这个方法

ThreadPoolExecutor:

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // 如果突然终止,那么 workerCount 不会被调整
    if (completedAbruptly)
        decrementWorkerCount();
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 完成的任务数量累加当前 worker 完成的任务数量
        completedTaskCount += w.completedTasks;
        // 移除当前 worker
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }
    /* 尝试终止 */
    tryTerminate();
    int c = ctl.get();
    if (runStateLessThan(c, STOP)) {
        // 判断线程是否没有突然终止
        if (!completedAbruptly) {
            // 确定最小线程数量
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            // 如果当前线程数量大于等于最小线程数量,直接返回
            if (workerCountOf(c) >= min)
                return;
        }
        // 增加一个线程
        addWorker(null, false);
    }
}

ThreadPoolExecutor:

final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        // 如果运行状态为 RUNNING 状态或者大于等于 TIDYING 或者(运行状态为 SHUTDOWN 状态并且队列不为空,直接返回)
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        if (workerCountOf(c) != 0) {
            // 中断一个闲置的线程
            interruptIdleWorkers(ONLY_ONE);
            return;
        }
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    // Executor 终止时调用的方法,默认实现什么都不做,留给子类实现,注意:要正确嵌套多个重写,子类通常应该在此方法中调用 super.terminated
                    terminated();
                } finally {
                    ctl.set(ctlOf(TERMINATED, 0));
                    // 唤醒所有等待的线程
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // 否则在失败的 CAS 上重试
    }
}

整个 addWorker 方法添加线程执行任务的流程到这里就完成了,接下来是添加 worker 失败的处理:
ThreadPoolExecutor:

private void addWorkerFailed(Worker w) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (w != null)
            // 移除当前 worker
            workers.remove(w);
        // 循环 CAS 递减 ctl 的 workerCount 字段,直到成功
        decrementWorkerCount();
        // 尝试终止,上文已经分析过这个方法
        tryTerminate();
    } finally {
        mainLock.unlock();
    }
}

到这里,整个 execute 方法执行过程的分析就完成了。为线程池提交任务还可以使用 submit 方法,使用 submit 提交的任务可以获取任务执行的返回值:
AbstractExecutorService:

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    // 将任务封装到 FutureTask 中
    RunnableFuture<T> ftask = newTaskFor(task);
    // RunnableFuture 接口继承了 Runnable 接口,所以可以使用 execute 方法来执行
    execute(ftask);
    // 返回执行结果
    return ftask;
}

最后是关闭线程池的相关实现,可以使用 shutdown 和 shutdownNow 两个方法来关闭线程池,区别是 shutdown 方法将执行平缓的关闭过程,不再接受新的任务,同时等待已经提交的任务执行完成,包括那些还未开始执行的任务。shutdownNow 方法将执行粗暴的关闭过程,它将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。
ThreadPoolExecutor:

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 检查调用者是否有权限中断 worker 线程
        checkShutdownAccess();
        // 将运行状态过渡到 SHUTDOWN,如果运行状态大于等于 SHUTDOWN,则保持不变
        advanceRunState(SHUTDOWN);
        // 中断所有闲置的线程,上文已经分析过
        interruptIdleWorkers();
        // shutdown 钩子方法,默认空实现,由子类覆盖,ScheduledThreadPoolExecutor 对其进行了覆盖来取消延迟任务
        onShutdown();
    } finally {
        mainLock.unlock();
    }
    // 尝试终止,上文已经分析过这个方法
    tryTerminate();
}

ThreadPoolExecutor:

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 检查调用者是否有权限中断 worker 线程
        checkShutdownAccess();
        // 将运行状态过渡到 STOP,如果运行状态大于等于 STOP,则保持不变
        advanceRunState(STOP);
        // 中断所有线程,即使处于活动状态,忽略 SecurityExceptions(在这种情况下,某些线程可能保持不中断)
        interruptWorkers();
        /* 移除队列中的任务,并返回这些任务 */
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

ThreadPoolExecutor:

private List<Runnable> drainQueue() {
    BlockingQueue<Runnable> q = workQueue;
    ArrayList<Runnable> taskList = new ArrayList<Runnable>();
    // BlockingQueue 的 drainTo 方法会移除此队列中所有可用的元素,并将它们添加到给定 collection 中
    q.drainTo(taskList);
    // 如果队列是 DelayQueue 或其他类型的队列,poll 或 drainTo 可能无法删除某些元素,则会逐个删除它们
    if (!q.isEmpty()) {
        for (Runnable r : q.toArray(new Runnable[0])) {
            if (q.remove(r))
                taskList.add(r);
        }
    }
    return taskList;
}

到这里,整个线程池 ThreadPoolExecutor 的源码解析就完成了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值