线程池核心源码阅读

目录

相关接口和实现类

工作线程Worker类

核心方法:execute( )

核心方法:addWorker( )方法


相关接口和实现类

由一个顶级接口 Executor ,两个核心子接口 ExecutorService、ScheduledExecutorService和一组实现类组成。

顶级接口Executor的作用是用来定义线程池中提交并执行线程任务的核心方法:execute( )方法。未来所有要提交的线程任务都由这个方法执行 。

ExecutorService接口作为子接口,在原有的基础上扩展了awaitTermination()、submit()、shutdown()等专门用于管理线程任务的方法。

AbstractExecutorService为ExecutorService的抽象实现类,为它的子类提供了submit()、invokeAll()等部分方法的公共实现。但是由于在不同线程池中的核心方法exuecte()执行策略不同,所以在AbstractExecutorService并未提供该方法的具体实现。常见子类有ThreadPoolExecutor和ForkJoinPool,实现了不同的线程池。

ThreadPoolExecutor线程池通过Worker工作线程、BlockingQueue阻塞工作队列以及RejectedExecutionHandler拒绝策略实现了一个标准的线程池;

ForkJoinPool是一个基于分治思想的线程池实现类,通过分叉(fork)、合并(join)的方式,将一个大任务拆分成多个小任务,并且为每个工作线程提供一个工作队列,减少竞争,实现并行的线程任务执行方式,所以ForkJoinPool适合计算密集型场景,是ThreadPoolExecutor的一种补充。

ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类,它是按照时间周期执行线程任务的线程池实现类,通常用于作业调度相关的业务场景。它使用DelayedWorkQueue延时工作队列,这是一个按照任务执行时间进行排序的优先级工作队列,所以这也是ScheduledThreadPoolExecutor能按照时间周期来执行线程任务的主要原因。

工作线程Worker类

线程池中每一个Worker对象,都代表其中的一个工作线程。

当线程池通过调用execute( )方法执行1个线程任务时,会调用addWorker( )方法创建一个Worker工作线程对象。并且会把创建好的Worker工作线程添加到HashSet<Worker> workers中,统一由线程池进行管理。(当前工作线程数小于核心线程数时)

通过源码我们看到,Worker类是 ThreadPoolExecutor类中的私有内部类,保存了每个Worker要执行的Runnable线程任务和Thread线程对象

当创建一个Worker时,会以构造方法的形式保存Runnable线程任务,同时通过 ThreadFactory线程工厂,为该Worker分配一个Thread。这样每个Worker都将通过这种形式绑定一个真正的Thread。

另外,当Thread被JVM调度执行时,线程会自动执行Worker的run( )方法,run( )方法内部通过调用runWorker( )方法,最终实现Worker保存的线程任务的执行。

值得重视的是:当Worker第一次执行完成线程任务后,这个Worker的工作线程并不会销毁,而是会以循环的方式,通过线程池的getTask( )方法获取阻塞工作队列中新的线程任务,并通过当前所绑定的Thread线程完成线程任务的执行,从而实现了线程池中线程的重用。

核心方法:execute( )

ThreadPoolExecutor线程池中,会通过execute(Runnable task)方法执行Runnable类型的线程任务。

ThreadPoolExecutor完整实现了Executor接口定义execute()方法,这个方法作用是执行一个Runnable类型的线程任务。整体的执行流程是:

  1. 首先通过AtomicInteger类型的ctl对象,获取线程池的工作状态和工作线程数;
  2. 然后判断当前的工作线程数;
  3. 如果当前的工作线程数小于核心线程数,则通过addWorker( )方法创建新的Worker工作线程,并将其添加至workers工作线程集合;
  4. 如果当前工作线程数大于等于核心线程数,并且线程池处于Running状态,那么会将线程任务缓存至workQueue阻塞工作队列,等待某个空闲工作线程获取并执行该任务;
  5. 如果工作队列也缓存任务失败,意味着工作队列已满。那么线程池则会重新通过addWorker( )方法尝试创建新的Worker;
  6. 这次的创建会判断当前工作线程数是否超出最大线程数。如果没有超出则创建;如果已经超出,则返回false,创建失败,下一个提交的线程任务如果想要执行,线程池会直接执行拒绝策略;

下面是部分源代码

public class ThreadPoolExecutor
{
    // 线程池执行Runnable线程任务
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();

        // 获取线程池的状态和工作线程数
        int c = ctl.get();

        // 工作线程的数量小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
            // 创建新的Worker工作线程
            if (addWorker(command, true))
                return;

            // 创建失败,重新获取线程池的状态和工作线程数
            c = ctl.get();
        }

        // 如果线程池处于RUNNING状态,缓存线程任务至工作队列
        if (isRunning(c) && workQueue.offer(command)) {

            // 任务缓存成功
            // 重新获取线程池的状态和工作线程数
            int recheck = ctl.get();

            // 如果线程池不是处于RUNNING状态,则删除任务
            if (! isRunning(recheck) && remove(command))
                // 执行拒绝策略
                reject(command);

                // 如果工作线程数等于零
                // 通过addWorker()方法检查线程池状态和工作队列
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }

        // 如果缓存线程任务至工作队列
        // 尝试创建新的工作线程
        // 创建时,判断工作线程数是否超出最大线程数
        // 如果没有超出,创建成功
        // 如果已经超出,创建失败
        else if (!addWorker(command, false))
            // 执行拒绝策略
            reject(command);
    }
}

核心方法:addWorker( )方法

在execute( )方法执行的过程中,会通过addWorker( )方法创建工作线程,用于执行当前线程任务。

通过源码我们发现,这个方法的整个执行过程可分为两个部分:检查线程池的状态和当前工作线程数,用于创建并执行工作线程。

1. 检查线程池当前运行状态和工作线程数量

private boolean addWorker(Runnable firstTask, boolean core) {
        // 第1部分:检查线程池的状态和工作线程数量
        // 循环检查线程池的状态,直到符合创建工作线程的条件,通过retry标签break退出
        retry:
        for (;;) {
        // 通过ctl对象,获取当前线程池的运行状态
        int c = ctl.get();
        int rs = runStateOf(c);

        // 如果线程池处于开始关闭的状态(获取线程任务为空,同时工作队列不等于空)
        // 则工作线程创建失败
        if (rs >= SHUTDOWN &&
        ! (rs == SHUTDOWN &&
        firstTask == null &&
        ! workQueue.isEmpty()))
        return false;

        // 检查工作线程数量
        for (;;) {
        // 通过ctl对象,获取当前线程池中工作线程数量
        int wc = workerCountOf(c);

        // 工作线程数量如果超出最大容量或者核心线程数(最大线程数)
        // 则工作线程创建失败
        if (wc >= CAPACITY ||
        wc >= (core ? corePoolSize : maximumPoolSize))
        return false;

        // 通过ctl对象,将当前工作线程数量+1,并通过retry标签break退出外层循环
        if (compareAndIncrementWorkerCount(c))
        break retry;

        // 再次获取线程池状态,检查是否发生变化
        c = ctl.get();  // Re-read ctl
        if (runStateOf(c) != rs)
        continue retry;
        // else CAS failed due to workerCount change; retry inner loop
        }
        }

        // 第2部分:创建并执行工作线程....
        }

2. 创建并执行工作线程

private boolean addWorker(Runnable firstTask, boolean core) {
        // 第1部分:检查线程池的状态和工作线程数量....
        // 第2部分:创建并执行工作线程....
        boolean workerStarted = false; // 工作线程是否已经启动
        boolean workerAdded = false;   // 工作线程是否已经保存
        Worker w = null;
        try {
        // 创建新工作线程,并通过线程工厂创建Thread线程
        w = new Worker(firstTask);

// 获取新工作线程的Thread线程对象,用于启动真正的线程
final Thread t = w.thread;
        if (t != null) {

// 获取线程池的ReentrantLock主锁对象
// 确保在添加和启动线程时的同步与安全
final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
        // 检查线程池状态
        int rs = runStateOf(ctl.get());
        if (rs < SHUTDOWN ||
        (rs == SHUTDOWN && firstTask == null)) {

        // 检查Thread线程对象的状态是否已经处于启动状态
        if (t.isAlive())
        throw new IllegalThreadStateException();

        // 保存工作线程
        workers.add(w);

        // 记录线程池曾经达到过的最大工作线程数量
        int s = workers.size();
        if (s > largestPoolSize)
        largestPoolSize = s;
        workerAdded = true;
        }
        } finally {
        mainLock.unlock();
        }

        // 添加工作线程后,正式启动线程
        if (workerAdded) {
        t.start();
        workerStarted = true;
        }
        }
        } finally {
        if (! workerStarted)
        addWorkerFailed(w);
        }

        // 返回线程启动状态
        return workerStarted;
        }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值