jdk-ThreadPoolExecutor(一)---基本变量和大致流程解析

之前测试CountDownLatch时,使用了线程池。

ExecutorService service = Executors.newFixedThreadPool(3);

service.submit(run);

service.shutdown();

基于此,今天来看看java给我们提供的线程池有哪些?作为码农,不能以会使用作为终极目标,了解源码觉得很有必要,通过源码,可以知道它的执行原理,可以知道哪些可为,哪些不可为,可以说这是内功,不是一两天就能就能练成的,而招式就是你的使用,没有内功的支持,即使你的招式再华丽,也没有威力,说不定一个小小的问题,就能威胁你的生命~~~~~~~~~~~~。所以内功和招式相辅相成,武侠里,有些人内功深厚,和谁比试都不会吃亏,单纯的招式不够看。。。题外话了。


翻开源码,可以看见java给我们提供的线程池 Executor,它是顶级接口,里面只有一个execute方法,所以它只是一个执行工具,真正的线程池接口是ExecutorService,作为面向接口编程的理解,那么它一定是指向它的实现类,它的实现类是由Executors里面的静态方法生成的。

翻看Executors没的静态方法,发现它们构建的对象其实是ThreadPoolExecutor,那么今天的主角就出来了,先来看看它吧,之前分析过队列的一些知识,CAS,看起来就不会费力了。


先来理解一下它里面的一些变量,对于下面的逻辑段理解有好处,内部使用了大量的位移操作,需要慢慢理解。

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//COUNT_BITS允许的最大线程数所占的位数 32-3 = 29,最低就是0位,最大是29位
private static final int COUNT_BITS = Integer.SIZE - 3;
//CAPACITY 允许的最大线程数,1 * 2^29 - 1
//00000000 00000000 00000000 00000001  其实也就是 1左移 29 位
//00100000 00000000 00000000 00000000  再减去 1
//000 11111 11111111 11111111 11111111
//前面三位是状态位,后面29位是线程数目位(为什么会这么分是因为AtomicInteger这个复合型变量)
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
//-1在计算机内部是32个1
//11111111 11111111 11111111 11111111  左移29位,
//111 00000 00000000 00000000 00000000  那么这边可以看见状态位其实是由高3位决定的,RUNNING的状态是 111
//该状态下线程池能接受新任务,并且可以运行队列中的任务
private static final int RUNNING    = -1 << COUNT_BITS;

//00000000 00000000 00000000 00000000
//000 00000 00000000 00000000 00000000 状态为 000
//该状态下的线程池不再接受新任务,但仍可以执行队列中的任务
private static final int SHUTDOWN   =  0 << COUNT_BITS;

//00000000 00000000 00000000 00000001
//001 00000 00000000 00000000 00000000  状态为 001
//以下状态下的线程池不再接受新任务,不再执行队列中的任务,而且要中断正在处理的任务
private static final int STOP       =  1 << COUNT_BITS;

//00000000 00000000 00000000 00000010
//010 00000 00000000 00000000 00000000 状态为 010
private static final int TIDYING    =  2 << COUNT_BITS;

//00000000 00000000 00000000 00000011
//011 00000 00000000 00000000 00000000 状态为 011
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
// CAPACITY 为 000 11111 11111111 11111111 11111111
// 取非操作 为  111 00000 00000000 00000000 00000000,这样的话再和c进行 与 操作,那么高3位的值就能原样保留,低29位置成0,那么c里面低29位全部为0
private static int runStateOf(int c)     { return c & ~CAPACITY; }

// CAPACITY 为 000 11111 11111111 11111111 11111111
// 获取workerCount,workerCount是低29位的值,高3位为0,不管.
private static int workerCountOf(int c)  { return c & CAPACITY; }

//传入的rs表示线程池运行状态runState,其是高3位有值,低29位全部为0的int,
//而wc则代表线程池中有效线程的数量workerCount,其为高3位全部为0,而低29位有值得int,
//将runState和workerCount做或操作|处理,即用runState的高3位,workerCount的低29位填充的数字,
//而默认传入的runState、workerCount分别为RUNNING和0。
private static int ctlOf(int rs, int wc) { return rs | wc; }


public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))  //关注此处,加入Worker
                return;
            c = ctl.get();    //失败之后尝试再次加入
        }
        if (isRunning(c) && workQueue.offer(command)) {   //workQueue为新增线程的队列
            int recheck = ctl.get();                      //成功加入之后再次检查状态
            if (! isRunning(recheck) && remove(command))
                reject(command);   //如果状态不一致,remove掉
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false); //自增空任务
        }
        else if (!addWorker(command, false))
            reject(command);   //直接reject掉
    }

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();   //再次获取,以免数据改变
            int rs = runStateOf(c);   //获取当前状态,这边不再叙述,上面已有分析

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                    ! (rs == SHUTDOWN &&
                            firstTask == null &&
                            ! workQueue.isEmpty()))
                //1. 当状态超过或者就是SHUTDOWN时,不再接收新进的线程
                //2. 当状态为SHUTDOWN时,  ! (rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()) 这个状态有点复杂
                //我们来看 需要 整个状态是 真 才能return false。
                //因此 rs == SHUTDOWN && firstTask == null && workQueue.isEmpty() 这个状态需要为假才行
                //那么在 rs 是 SHUTDOWN 的情况下 firstTask == null()为假,或者 !workQueue.isEmpty()为假就行
                //2.1 firstTask == null()为假 ,就是当前任务存在
                //2.2 workQueue.isEmpty()为真 ,任务队列空的
                //就是当状态是SHUTDOWN时,当前任务存在及 任务队列为空或者任务队列有任务时,不允许添加进来
                return false;

            for (;;) {
                //获取当前数量
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                        wc >= (core ? corePoolSize : maximumPoolSize))
                    //大于允许的最大值,也是不允许添加进来
                    return false;
                //如果允许添加,CAS操作将Count+1
                if (compareAndIncrementWorkerCount(c))
                    break retry; //跳出retry
                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;
        Worker w = null;    //Work是个内部类,暂时不分析结构,新建处的线程都是加入到Worker内
        try {
            final ReentrantLock mainLock = this.mainLock;
            w = new Worker(firstTask);   //new出Worker,内部将状态设置成-1,继承自AQS,因此关联到AQS内去分析-1状态
            final Thread t = w.thread;   //获取内部创建的thread,也是通过将Runnable封装到Thread内返回
            if (t != null) {
                //新建成功线程加锁
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    //重新获取状态,以免状态发生变化
                    int c = ctl.get();
                    int rs = runStateOf(c);

                    if (rs < SHUTDOWN ||
                            (rs == SHUTDOWN && firstTask == null)) {
                        //1.这个地方其实就是在说在Running态下能新增
                        //2.或者在SHUTDOWN下但是新增任务是空的时候能进入,SHUTDOWN状态是不能新增任务的,但是需要执行线程池内剩余的任务
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);   //加入workers
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;  //记录最大线程数
                        workerAdded = true;  //将标志记录为true
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();  //如果添加进入了,启动
                    workerStarted = true;  //启动标志设置为true
                }
            }
        } finally {
            if (! workerStarted)
                //如果启动失败立即回退,从workers中删除,尝试结束线程
                addWorkerFailed(w);
        }
        return workerStarted;
    }

private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w); //remove
            decrementWorkerCount();  //CAS减1
            tryTerminate();   ///尝试结束
        } finally {
            mainLock.unlock();
        }
    }

    final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                    runStateAtLeast(c, TIDYING) ||
                    (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                //1. isRunning状态下直接返回
                //2. c 状态 >=2 时,忽略
                //3. 如果是SHUTDOWN时,只要队列任务不空,就返回不做操作
                return;
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);   //尝试去中断一个空闲线程。
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        //如果此时线程数量是0 了,就将状态设置成TERMINATED
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll(); //通知其他等待的线程
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }


    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {  //注意此处,执行任务的线程是互斥的锁定对象,因此这边如果能获取到锁的话,可以认定是空闲线程
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

本篇文章大致分析了一下execute的方法,从整个方法入手我们可以直观的看见一些东西,那我们来总结一下ThreadPoolExecutor的一些流程。

1.如果当前线程池有效线程数目小于corePoolSize的话,corePoolSize就是我们在构建时传入的允许的线程池的大小(包括正在运行的和空闲的线程数目)。那么就尝试添加新的worker线程处理command,调用有效线程数组时workerCountOf()方法,第二个参数true是作为边界值的约束条件使用,成功添加直接返回,否则再次获取clt的值c,也就是状态。

2.根据c判断出当前线程池是否为RUNNING状态。即既能接收新任务,又能处理队列中任务的状态,此时的c是重新获取的状态,多线程的处理是比较复杂的。通过offer方法加入到队列中,如果成功添加进入了队列中。那么需要再次获取状态,检查当前线程池的状态是不是RUNNING,这边再次做检查的目的,也就是为了判断出当做过一次添加线程进入队列之后,需要保证此时线程池任然处于一个有效状态。如果不是RUNNING状态的话,从队列中移除刚刚添加的线程,并且将当前任务拒绝掉。如果失败了,那么就在当前线程池中的数目是0时添加一个worker线程,但是不携带任务。

3.最后的逻辑在什么条件都不满足时,强行去新增一个线程处理任务,但是还是失败了直接拒绝掉。

整体理解的话不是很难啊,下一篇重点来分析内部的一些构造和一些具体的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值