从源码角度来分析JAVA线程池的实现(核心属性和方法)

1.引言

在上篇博客《浅谈JAVA线程池实现原理及与一般池化技术的区别》中,我介绍了java线程池的基本原理以及一下简单的用法,但感觉还是不很透彻,这篇博客我打算从源码角度来分析JAVA线程池的实现。

2. JAVA线程池源码解析

1.ThreadPoolExecutor的核心属性和方法

ThreadPoolExecutor中我认为比较重要的属性和方法有:

  • 内部类:Worker,线程池的工作线程类
  • workers属性:一个Set集合,储存线程池的所有工作线程Worker;
  • execute方法:用于在将来的某个时间执行给定的任务。任务可以在新线程或现有池线程中执行;
  • addWorker方法:假如到当前线程池,开启线程并执行;
  • runWorker:执行task;
  • processWorkerExit:清理线程池中的线程

2.ThreadPoolExecutor#Worker内部类

Worker,是用来实现线程池中的内部工作线程的。它的定义如下:

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        private static final long serialVersionUID = 6138294804551838833L;
        final Thread thread;
        Runnable firstTask;
        volatile long completedTasks;
        // 省略部分代码
   }     

可以看出,它继承 AbstractQueuedSynchronizer,即AQS,主要是实现一个不可重入的独占锁,避免并发时资源的竞争;实现了 Runnable 接口,说明是一个线程对象;thread 属性,具体执行任务的线程;
firstTask 属性,记录 Worker 执行的第一个任务。

3.ThreadPoolExecutor#workers属性

JAVA线程池中维护了一个workers的Set集合,储存了线程池所有的工作线程,并且加了锁,只有拿到mainLock锁才能访问。

    private final ReentrantLock mainLock = new ReentrantLock();

    /**
     * Set containing all worker threads in pool. Accessed only when
     * holding mainLock.
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();

    /**
     * Wait condition to support awaitTermination
     */
    private final Condition termination = mainLock.newCondition();

    /**
     * Tracks largest attained pool size. Accessed only under
     * mainLock.
     * 记录了workers集合的大小
     */
    private int largestPoolSize;

4.ThreadPoolExecutor#execute方法

我们先看一下之前我画的那个execute的执行流程:
在这里插入图片描述
下面是execute方法的源码:

public void execute(Runnable command) {
        //校验任务不能为空
        if (command == null)
            throw new NullPointerException();
        //根据c的值,来判断线程池的状态、线程的数量
        int c = ctl.get();
        //1.如果当前线程池中的线程数量小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
            // 1-1.添加一个线程到核心线程 command代表我们提交的任务,true代表是核心线程
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //以下的代码代表当前线程池中的线程数量大于或者等于核心线程数,那就不能将新的任务直接创建一个核心线程了
        //需要加入队列或者加入到最大线程中
        //2.如果线程池是运行状态,并且队列还没有满,就把任务添加到队列中,等到消费
        if (isRunning(c) && workQueue.offer(command)) {
            //2-1.这里使用了双重检验机制
            int recheck = ctl.get();
            // 2-2.如果线程池当前不在运行状态并且能够删除刚刚加入到队列中的任务,就执行拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //2-3.如果当前线程池中没有运行的线程(由于某种原因,线程终止了),就新起一个线程
            // 这里第一个参数firstTask为null,是因为该任务已经通过offer添加至队列中了
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //3.如果线程池中的阻塞队列已经满了,试图假如到非核心线程处理任务
        else if (!addWorker(command, false))
        //3-1.如果超过了最大核心数,就执行拒绝策略
            reject(command);
    }

5.ThreadPoolExecutor#addWorker方法

这个方法主要是说,正常情况下会创建worker(新线程)去处理新任务

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //判断是否要创建新的工作线程
            //1.如果线程池的运行状态是STOP,TIDYING,TERMINATED,就
            // 直接返回false(因为这些条件下要求 清空队列,正在运行的任务也要停止)
            //2.如果线程池的运行状态是SHUTDOWN并且(firstTask!=null || 队列为空),直接返回false,即在
            //SHUTDOWN状态下, 想要创建一个firstTask为空的新worker,需要确保队列不为空(队列为空就意味着这个新的worker暂时还没有任务可以执行,所以也没有创建worker的必要, 因为这个worker是用来消化队列中的任务)
            // 大部分情况下,我们需要新创建的worker的firstTask都有初始化任务, 在SHUTDOWN状态下,就不允许在创建worker了,直接返回false
            if (rs >= SHUTDOWN &&
                    ! (rs == SHUTDOWN &&
                            firstTask == null &&
                            ! workQueue.isEmpty()))
                return false;

            for (;;) {
                // 计算worker的数量
                int wc = workerCountOf(c);
                // 如果worker数量已经超过指定核心线程数大小,则不允许创建
                if (wc >= CAPACITY ||
                        wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                // 尝试cas累加worker的数量,如果成功就跳出最外层循环
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                // 本次cas失败,表明ctl已经变了,检查线程池状态,如果状态变了就跳到最外层重新执行一次
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
        //如果可以创建新的工作线程
        boolean workerStarted = false;
        boolean workerAdded = false;
        ThreadPoolExecutor.Worker w = null;
        try {
            w = new ThreadPoolExecutor.Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    // 线程池运行状态
                    int rs = runStateOf(ctl.get());
                    //状态rs < SHUTDOWN表明是RUNNING状态或者如果线程池的状态是SHUTDOWN,
                    //那么创建的worker是用来处理队列中的任务,因此需要满足firstTask == null
                    if (rs < SHUTDOWN ||
                            (rs == SHUTDOWN && firstTask == null)) {
                        // 如果线程提前start则认为是异常状态
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //加入到线程池
                        workers.add(w);
                        int s = workers.size();
                        // 记录一下线程池在运行中线程数量的最大值
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    // 启动worker工作线程
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                // 如果添加worker失败了
                addWorkerFailed(w);
        }
        return workerStarted;
    }

6.ThreadPoolExecutor#runWorker方法

该方法的作用就是woker工作线程读取任务,执行task。

/**
     * woker工作线程读取任务,执行task
     * @param w
     */
    final void runWorker(ThreadPoolExecutor.Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            // 如果task的来源是firstTask(直接启动的工作线程)或者是队列
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                // 如果线程池是STOP及之后的状态,需要确保它是中断的
                // 如果是STOP之前的状态,就要确保它不能被中断(如果有的话就要清除中断标志,Thread.interrupted会清除中断标志)
                if ((runStateAtLeast(ctl.get(), STOP) ||
                        (Thread.interrupted() &&
                                runStateAtLeast(ctl.get(), STOP))) &&
                        !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    // 执行成功的任务数量++
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            // 处理worker退出
            //  一种是异常退出
            //  一种是普通线程(非核心),空闲时间到了退出
            processWorkerExit(w, completedAbruptly);
        }
    }

7.ThreadPoolExecutor#runWorker方法processWorkerExit

 /**
     * 处理工作线程woker的退出
     * 对worker执行结束之后,清理掉当前worker之后考虑是否采取用新的worker来替换
     * @param w
     * @param completedAbruptly
     */
    private void processWorkerExit(ThreadPoolExecutor.Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 当前worker完成的task数量累加
            completedTaskCount += w.completedTasks;
            // 从当前线程池的 Set中移除当前worker
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        // 每次worker结束后都要尝试终止线程池,在某个时刻worker都被清理了并且达到了线程池终止的条件
        // 就可以从这里结束
        tryTerminate();
        int c = ctl.get();
        // 如果线程池状态小于STOP
        if (runStateLessThan(c, STOP)) {
            // 如果不是异常
            // 如果用户任务发生了异常,尝试替换worker
            // 或者核心线程数量小于corePoolSize,尝试添加worker
            // 或者队列非空,但是已经没有worker了,尝试添加worker
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            // 这里新添加worker,没有初始化的firstTask, 这里worker处理的任务来自于队列
            addWorker(null, false);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值