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

来源:互联网 发布:手机淘宝的试用在哪里 编辑:程序博客网 时间:2024/06/05 00:10

之前测试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 状态为 010private static final int TIDYING    =  2 << COUNT_BITS;//00000000 00000000 00000000 00000011//011 00000 00000000 00000000 00000000 状态为 011private 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位全部为0private 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.最后的逻辑在什么条件都不满足时,强行去新增一个线程处理任务,但是还是失败了直接拒绝掉。

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

原创粉丝点击