jdk1.8 ThreadPoolExecutor解析

execute方法
1.工作线程数<核心线程数
2.否则将任务添加到阻塞队列
3.队列满了并且线程数小于最大线程,则创建线程
4.超过最大线程数,直接拒绝

        public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            //ctl高三位表示线程池状态,低29位表示线程数量
            int c = ctl.get();
            //工作线程数小于核心线程数
            if (workerCountOf(c) < corePoolSize) {
                /**
                 * addWorker失败原因
                 * 1.存在多线程并发
                 * 2.外部线程改变了线程池状态
                 */
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            /**
             * 工作线程数大于等于核心线程数或者addWorker失败,
             * 判断线程池状态  如果是运行状态则添加任务到阻塞队列
             */
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                /**
                 * 重复判断主要是因为两个if之间可能被外部线程改变了线程池运行状态,这时需要移除新加到队列的任务
                 *
                 * */
                if (! isRunning(recheck) && remove(command))
                    //移除成功则拒绝任务
                    reject(command);
                /**
                 * 1.状态是运行状态
                 * 2.状态不是运行态并且移除任务失败
                 * 上述两种情况会判断线程数量是否为0,防止出现异常导致线程死亡
                 */
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            /**
             * 线程池不是运行状态(有可能被外部线程shutdown)则直接拒绝
             * 队列满了,则判断线程数是否小于最大线程。
             * 小于则开启新的线程处理任务,否则超过最大线程数则拒绝任务
             */
            else if (!addWorker(command, false))
                reject(command);
        }

addWorker方法
主要作用就是将任务封装成worker对象并启动线程

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

                /**
                 * 再次判断线程池状态
                 * 1.rs>SHUTDOWN
                 * 2.rs=SHUTDOWN && firstTask != null
                 * 3.rs=SHUTDOWN && workQueue.isEmpty()
                 * 上述三种情况都会失败
                 * 线程池状态为SHUTDOWN时只有提交的任务为null并且堵塞队列还有任务没有处理完时才会继续执行
                 * (也就是说线程池shutdown时,如果堵塞队列还有任务没有处理完毕则会继续执行,但是不会接收新的任务入队)
                 */
                if (rs >= SHUTDOWN &&
                        ! (rs == SHUTDOWN &&
                                firstTask == null &&
                                ! workQueue.isEmpty()))
                    return false;




                //这个循环主要判断线程数量
                for (;;) {
                    int wc = workerCountOf(c);
                    //判断线程池线程数量是否超出
                    if (wc >= CAPACITY ||
                            wc >= (core ? corePoolSize : maximumPoolSize))
                        return false;
                    //最重要的一个步骤:线程数量没有超出,通过CAS将线程数+1
                    if (compareAndIncrementWorkerCount(c))
                        break retry;

                    //CAS失败说明可能已经有线程改过ctl的值,重新获取ctl
                    c = ctl.get();
                    //判断线程池状态是否改变,改变了继续下一次循环
                    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 {
                        int rs = runStateOf(ctl.get());

                        /**
                         *再次检查线程池状态,防止创建worker过程中被外部线程修改
                         */
                        if (rs < SHUTDOWN ||
                                (rs == SHUTDOWN && firstTask == null)) {
                            if (t.isAlive())
                                throw new IllegalThreadStateException();
                            //将worker添加到hashset中,记录worker数量
                            workers.add(w);
                            int s = workers.size();
                            if (s > largestPoolSize)
                                largestPoolSize = s;
                            workerAdded = true;
                        }
                    } finally {
                        mainLock.unlock();
                    }
                    //如果添加成功,主线程会启动worker线程
                    if (workerAdded) {
                        t.start();
                        workerStarted = true;
                    }
                }
            } finally {
                //启动失败,进行后续操作
                if (! workerStarted)
                    addWorkerFailed(w);
            }
            return workerStarted;
        }

runWorker方法
线程启动会执行的具体方法

        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 {
                //首先执行worker内部的任务,执行结束会从队列里面获取任务执行
                while (task != null || (task = getTask()) != null) {
                	//设置独占锁
                    w.lock();

                    /**
                     * 1.runStateAtLeast(ctl.get(), STOP)&&!wt.isInterrupted()成立
                     *  说明当前线程池状态>=stop&&当前线程没有设置中断状态,则需要给当前线程设置中断状态
                     * 2.Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP)
                     *  Thread.interrupted()表示获取当前中断状态并设置中断位为false
                     *  这里的主要目的在于将线程中断状态强制刷新为false
                     */
                    if ((runStateAtLeast(ctl.get(), STOP) ||
                            (Thread.interrupted() &&
                                    runStateAtLeast(ctl.get(), STOP))) &&
                            !wt.isInterrupted())
                        wt.interrupt();
                    try {
                        //提供的扩展方法,可以自己实现
                        beforeExecute(wt, task);
                        Throwable thrown = null;
                        try {
                            //具体执行的run方法,注意执行task任务不会存在并发
                            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();
                    }
                }
                //getTask()返回null会走正到这里,线程执行完正常退出
                //否则表示执行task.run()出现异常
                completedAbruptly = false;
            } finally {
                //completedAbruptly ==false 表示线程没有获取到任务  正常退出
                //completedAbruptly == true  表示执行过程出现了异常  异常退出
                processWorkerExit(w, completedAbruptly);
            }
        }

getTask方法
阻塞队列获取任务的方法
最大线程数采用poll方式获取任务,如果在指定时间获取不到任务,后面会执行线程退出
核心线程数默认采用take方式获取任务,获取不到任务会阻塞直到有任务进入阻塞队列

        /**
         * 返回null的情况
         * 1.rs >= STOP线程池状态>=stop
         * 2.rs == SHUTDOWN&&workQueue.isEmpty() 线程池状态是shutdown状态并且线程池空了
         * 3.工作线程超过了最大线程数
         * 4.工作线程超过了核心线程数,并且获取任务超时了可能被回收
         * 5.allowCoreThreadTimeOut 设置为true,表示核心线程获取任务超时也会被回收
         */
        private Runnable getTask() {
            boolean timedOut = false;

            for (;;) {
                int c = ctl.get();
                int rs = runStateOf(c);

                /**
                 * 1.rs >= STOP 线程池状态大于等于stop
                 * 2.rs == SHUTDOWN && workQueue.isEmpty() 线程池状态等于shutdown并且队列为空
                 * cas方式对工作线程-1
                 * 上面两种情况表示线程池不用继续处理了,直接返回
                 */
                if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                    decrementWorkerCount();
                    return null;
                }

                //走到这里说明线程池是running状态或者线程池是shutdown状态并且队列还有任务需要处理
                int wc = workerCountOf(c);


                //timed==true,表示核心线程也可以被回收,并且采用poll超时方式获取任务
                //timed == false,否则会无限制等待方式获取任务
                boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

                /**
                 * 1.wc > maximumPoolSize 回收最大线程
                 *  timed && timedOut  表示以poll方式获取任务并且超时了
                 * 2.wc > 1 说明还有其他线程,则当前线程可以被回收
                 *  wc==1 &&workQueue.isEmpty() 队列空了,当前线程也可以被回收
                 */
                if ((wc > maximumPoolSize || (timed && timedOut))
                        && (wc > 1 || workQueue.isEmpty())) {
                    if (compareAndDecrementWorkerCount(c))
                        return null;
                    continue;
                }

                try {
                    //timed==true 表示阻塞一段时间无论取到任务与否都会返回
                    //timed==false 表示无限制阻塞直到取到任务
                    Runnable r = timed ?
                            workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                            workQueue.take();
                    if (r != null)
                        return r;

                    //走到这说明获取任务超时了
                    timedOut = true;
                } catch (InterruptedException retry) {
                    timedOut = false;
                }
            }
        }

allowCoreThreadTimeOut
可以设置核心线程数采用poll方式获取任务,也就是说在指定时间内获取不到任务核心线程数也可以被回收

    public void allowCoreThreadTimeOut(boolean value) {
        if (value && keepAliveTime <= 0)
            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
        if (value != allowCoreThreadTimeOut) {
            allowCoreThreadTimeOut = value;
            if (value)
                interruptIdleWorkers();
        }
    }

另外说一下execute和submit区别?
1.submit会将提交的callable或runnable任务封装成futuretask,而execute不会。
2.execute执行出现异常会抛出,而submit不会抛出异常,需要拿到futuretask调用get方法才会抛出异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值