ThreadPoolExecutor解读笔记

写在2017.09.19

最近新工作稳定些(加班还是忙成狗),某些晚上11点后还是有点自己的时间写写博客,最近对JUC中有些技术有些热情,将尝试解读下,定个小目标解读到AQS,先从用得多知道其实并不多的ThreadPoolExecutor进行解读。

本文从小的case引出为什么使用线程池,怎么使用,线程池的内部原理是什么,参数怎么设置。当然都是我个人理解,如果有异议也请指教下,相互学习。

(18/7/30有点变更,之前的博文有些地方不是太深入,本次有点改动,并且重新排版)。

话题引出

在请求-相应模式中,不使用线程池模式,有2中模式可供选择:

case1. B收到A用户请求后入队列,B启动单独任务轮询队列挨个处理,并做返回

case2. B收到A请求后,对每个请求新建一个线程处理

如果用户请求多,并发大,Case1和Case2会发生什么情况?

Case1:单任务处理,不能有效利用CPU,可能大量请求堆积在队列,导致堆积的任务超时;如果队列满了以后,怎么处理,直接拒绝?丢掉?。。。

Case2:计算机上CPU是有限的,如果请求过大,线程过大,导致线程间的切换耗时较大,系统无法在创建线程,JVM虚拟机方法栈stackOverFlowError,甚至因为大量线程创建对象,导致系统卡顿。

进一步疑问

1.每处理一个请求就要创建一个线程然后销毁,系统资源开销大,系统(CPU 内存)表示扛不住

2.线程处理时,如果遇到异常,请求就丢失了(有没有可能记录下)

3.瞬时并发请求高,并发的线程数大,系统压力大下游调用游系统也会造成较大压力

4.这么多线程,怎么优雅停止线程?使用信号量,或使用线程中断方法,太复杂了吧。

还有其他....

解决方案就是大家知道的容器(即pool)作为请求的存储、中转调度,重复利用线程,避免频繁创建和销毁。

1.因为池子有容量,适当的容量(线程数)起到资源的重复利用,线程的创建销毁就能得到减少

2.池子能够调节容器的大小,瞬时洪峰到来能转移到池子中系统处理能力内得到处理,避免了对系统的冲击

3.当池子满时,我们可以有多种处理方式:转移,丢弃,拒绝。。。

还应关注

1.重启时是否会丢失?池子中数据是否可以持久化的?请求序列化和反序列化的方法?

2.请求入池,线程拉取请求的策略是什么?(FIFO,FILO...)池子的并发策略?(锁,并发队列...)

3.工作线程是否会因为处理请求异常而中断? 处理失败的请求,任务降级的策略是什么?(重新入池:从队头进,从队尾进,任务降级,重试次数...)

4.请求过大,超过负荷,池子的降级策略又是怎么实现?

5.线程的优先级?

6.下面场景又要怎么解决:

(1)并发数量大,RT时间短,如淘宝,天猫的访问每天的访问达到100多亿次

(2)并发数小,RT时间长,如后台程序对几十亿买家数据进行打标,对不同的标发放优惠券并发短信

(3)并发数大,RT时间长(有问题了)

。。。(暂时想到这些,文章不能面面俱到,请见谅)

JDK中的解决方案

JDK中为以上的问题提供线程池,位于java.util.concurrent包中。

线程池的使用类型

1.Executors#newFixedThreadPool(int nThreads) 固定线程数运行

2.Executors#newSingleThreadExecutor() 单线程池

3.Executors#newCachedThreadPool() 无限大小线程池,最多可到2^29个线程。

4.Executors#newSingleThreadScheduledExecutor() 调度线程池

ThreadPoolExecutor

无论是使用何种类型的线程池,其底层均是使用ThreadPoolExecutor来实现,从ThreadPoolExecutor类可以解读到线程池状态,如何处理任务,如何停止。

线程池状态解读

线程状态

image

线程池状态

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    //线程池线程容量
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

上面的代码可以看出,线程池使用ctl 作为线程的counter,ctl的高位存储表示线程池状态,其中2^29表示SHUTDOWN ,2^30表示STOP ,2^31表示TIDYING ,2^32表示TERMINATED。

状态图如下:


image

ThreadPoolExecutor构造函数解读

ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler)

JDK官方文档描述:


If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full

If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.

If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread

If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.

【corePoolSize】----核心线程数,线程提交时,即使运行中的线程+空闲线程数

【maximumPoolSize】----只有在队列满时,线程数小于maximumPoolSize,创建新的线程,线程数>corePoolSize时在keepAliveTime时间内从队列中获取不到任务,线程将被销毁

【keepAliveTime】----见maximumPoolSize和corePoolSize的描述。

【unit】----keepAliveTime的单位时间

【workQueue】----阻塞队列,线程池达到核心线程数时入此队列,工作线程不断地从队列中获取任务,如果是allowCoreThreadTimeOut=true或工作线程数大于corePoolSize,在keepAliveTime时间内获取不到任务的线程将会销毁。队列类型见后面描述。

【threadFactory】----线程工厂,用于创建新线程(使用地方见Worker的构造方法,本文后后部分有介绍)。

【handler】----线程拒绝策略,需实现RejectedExecutionHandler接口,常见策略本文也将介绍。

workQueue类型

1.SynchronousQueue: 直接提交队列,每个 put 必须等待一个 take,配合着无界线程池(Executors#newCachedThreadPool())使用。

2.LinkedBlockingQueue:链表实现的有界队列阻塞队列,按先进先出的原则对元素进行排序(FIFO),队列满时存放元素的线程会被阻塞,队列空时会阻塞从队列中取元素的线程。默认值为Integer.MAX_VALUE(建议不使用,流量洪峰时并没有调用更多的线程去处理请求,如果峰值持续时间较长,任务会在队列里积压,可能会导致超时,甚至于所有新任务都要排队,最终所有请求超时)。这里有原理解析。

3.ArrayBlockingQueue:用数组实现的有界阻塞队列,按先进先出的原则对元素进行排序(FIFO),队列满时会增加线程到最大值。这里有原理解析。

4.PriorityBlockingQueue:无界阻塞优先级队列(原理介绍)

RejectedExecutionHandler拒绝策略

  • AbortPolicy ---- 拒绝新的新请求,异常抛出
    /**
     * A handler for rejected tasks that throws a
     * {@code RejectedExecutionException}.
     */
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
  • CallerRunsPolicy ----直接在execute方法外运行该任务,如果线程池停止则抛弃该任务
   /**
     * A handler for rejected tasks that runs the rejected task
     * directly in the calling thread of the {@code execute} method,
     * unless the executor has been shut down, in which case the task
     * is discarded.
     */
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }
  • DiscardPolicy----丢弃该任务,不抛出异常
    /**
     * A handler for rejected tasks that silently discards the
     * rejected task.
     */
    public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
  • DiscardOldestPolicy ---- 丢弃存在队列中本该要执行的请求,将新的请求加入队列中
  /**
     * A handler for rejected tasks that discards the oldest unhandled
     * request and then retries {@code execute}, unless the executor
     * is shut down, in which case the task is discarded.
     */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
  • 可以自定义——实现RejectedExecutionHandler接口,内部实现rejectedExecution(Runnable r, ThreadPoolExecutor e) 。

想了解更多可以参考:http://blog.csdn.net/pozmckaoddb/article/details/51478017

源码分析

提交线程

使用execute 和submit。

execute

当线程数小于corePoolSize时,新请求不会进入队列,会直接创建新线程处理;如果运行的线程数等于corePoolSize,且队列未满,新请求将进入队列,工作线程不断从队列中获取任务执行;队列满时,当工作线程数小于maximumPoolSize,线程池创建新线程;当工作线程数等于maximumPoolSize,且队列满,新的任务会走拒绝策略。当然在向线程池提交任务或是线程从队列中获取任务时,会检查线程池状态,如果线程池处于SHUTDOWN及以上状态时,新任务将不能提交,被拒绝;如果线程池是SHUTDOWN状态且队列是空队列或STOP及以上状态,线程销毁。

    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.
         */
        
        // ctl为当前线程数量,AtomicInteger类型
        int c = ctl.get();

        //int workerCountOf(int c)  { return c & CAPACITY; }比较简单,
        //线程数量最多CAPACITY(为2^29-1)个
        //当前线程数小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
            //如果线程数小于核心线程数,则新建线程并运行,后面有详细描述
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //线程池处于SHUTDOWN以下状态(非停止状态)且队列未满
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            //如果线程池非工作状态,则尝试从队列移除,如果能移除则执行拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //当前线程池内线程数为0
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }
 private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {//外循环
            int c = ctl.get();
            //ctl低位表示线程数,高位存储线程池状态:2^29表示线程池SHUTDOWN
            //2^30表示STOP,2^31表示TIDYING,2^32表示TERMINATED
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //线程池状态(SHUTDOWN,TIDYING,TERMINATED),状态且是空队列,返回false
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {//内循环
                int wc = workerCountOf(c);
                //以下情况返回false,不新建线程
                //1.线程容量已达到2^29-1
                //2.若当前线程数小于核心线程数才调用此方法时,
                //再check发现前线程数大于核心线程数
                //3.当前线程数 >= 最大线程数
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //对线程计数+1成功,退出外循环,继续执外循环后的操作
                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
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //构造Worker(该类继承AQS和Runnable,见后文):
            // 若是execute方法中是未达到核心线程数时调用,
            //firstTask非null是任务,大于核心线程数时调用firstTask是null
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                //互斥锁,保证同一时间只有1个调用
                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());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                       //将线程存放workers(HashSet )中,
                       //workers中存放的是所有工作线程
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                //启动线程
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            //启动线程失败,从workers删除,如线程池是TIDYING尝试停止线程池
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

work实现

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
       。。。
        Worker(Runnable firstTask) {
           //设置QAS同步状态,-1表示初始状态,
          // 1表示lock状态(有任务在执行中),0表示unlock(没有任务正在执行)
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            //新建Thread线程
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
           //该方法轮询从队列中获取任务,并执行任务的run方法,详细见后文
            runWorker(this);
        }
。。。
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
           //任务未提交到队列或是从队列中取到任务非空
            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及以上状态将线程中断
                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.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 {
                       //和beforeExecute实现一致,作用差不多
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    //释放锁
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            //线程销毁时候执行
            processWorkerExit(w, completedAbruptly);
        }
    }
private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

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

            // Check if queue empty only if necessary.
            //SHUTDOWN以上状态且(状态是STOP及以上或是空队列)时,线程数-1
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
           //调用ThreadPoolExecutor#allowCoreThreadTimeOut(true)或线程数>核心线程数,
           //在运行线程池队列为空时允许线程在keepAliveTime时间后销毁,从works中移除
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
               //从阻塞队列中获取任务。
               //若存在设置核心线程数可超时销毁或线程数大于核心线程数
               //时,在keepAliveTime时间内获取;否则从队列阻塞直到获取到任务
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                //超时未获取到,设置timedOut=true
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
线程销毁时候执行,其中completedAbruptly表示因用户异常导致的线程结束
private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            //从HashSet中删除线程
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        //见后文分析
        tryTerminate();

        int c = ctl.get();
        //在RUNNING和SHUTDOWN状态时,线程池中允许的线程数min , 
        //若当前线程数>min ,该线程自动销毁;否则运行在线程池和对列允 
        //许的情况下,新建线程来保证达到核心线程数
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }
final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            //运行,TIDYING或TERMINATED、SHUTDOWN状态且队列不为空
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            //SHUTDOWN且队列为空或STOP状态时,将Worker中所有线程执行interrupt方法
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                //CAS保证同一时间只有一个线程中将线程池变成TIDYING状态
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        //空方法,扩展使用,如打日志,统计,收集工作线程信息等。
                        terminated();
                    } finally {
                         //将线程池变成TERMINATED状态
                        ctl.set(ctlOf(TERMINATED, 0));
                        //一般停止线程池时通常会使用awaitTermination()方法,如
                       //果线程池未能及时停止,将wait,这里的signalAll作用类似
                       //notifyAll(),去唤醒等待的线程
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

submit

与execute方法相比,submit参数除了Runnable参数还能接收Callable参数;

    public Future submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public  Future submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public  Future submit(Callable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
 protected  RunnableFuture newTaskFor(Runnable runnable, T value) {
        return new FutureTask(runnable, value);
    }
上面的代码可以看出,将提交的任务(假设task)重新构造出一个新的任务FutureTask(FutureTask继承RunnableFuture,RunnableFuture继承自Runnable和Future),并调用execute方法,线程池线程执行时将调用FutureTask的run方法(具体请看上面所述中Worker#runWorker()方法),FutureTask#run()内部又去调用提交任务的call()方法,通过RunnableFuture#get()方法几个获取call()的返回值。

同execute方法相比,submit提交的线程,无论发生异常以否,都会有返回值Future(如发生异常,异常会被吃掉,结果值会被包装在Future中),通过Future可以取消任务,获取返回值,获得执行完成的时间等。

FutureTask

public class FutureTask implements RunnableFuture {
。。。
 /** The underlying callable; nulled out after running */
    private Callable callable;
    /** The result to return or exception to throw from get() **/ 
   //回值存在outcome,通过get()获取
    private Object outcome; // non-volatile, protected by state reads/writes
    /** The thread running the callable; CASed during run() */
    private volatile Thread runner;
    /** Treiber stack of waiting threads */
    //若任务未执行完成,外部通过get()方法获取call()方法返回值的线程将阻塞入栈
    private volatile WaitNode waiters;

。。。
public FutureTask(Callable callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

public FutureTask(Runnable runnable, V result) {
       //适配器模式,将Runnable转call(),call()方法调用任务的run()
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
。。。
public void run() {
       //线程非NEW状态或使用UNSAFE设置当前的状态不能成功,返回
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable c = callable;
            //再次检查,确保线程是NEW状态时执行
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
            //任务设置成完成,然后将对outcome设价成result,并将waiters上的所有阻塞线程unpark   
            if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

 /**
     * Ensures that any interrupt from a possible cancel(true) is only
     * delivered to a task while in run or runAndReset.
     */
    private void handlePossibleCancellationInterrupt(int s) {
        // It is possible for our interrupter to stall before getting a
        // chance to interrupt us.  Let's spin-wait patiently.
       //cancel(true)调用时,如果任务还没运行,任务状态此时为
       //INTERRUPTING,以下的方法会让出CPU时钟直到状态不为INTERRUPTING
       if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                Thread.yield(); // wait out pending interrupt

        // assert state == INTERRUPTED;

        // We want to clear any interrupt we may have received from
        // cancel(true).  However, it is permissible to use interrupts
        // as an independent mechanism for a task to communicate with
        // its caller, and there is no way to clear only the
        // cancellation interrupt.
        //
        // Thread.interrupted();
    }

//mayInterruptIfRunning=true时,对线程执行interrupt()方法,标记任务为INTERRUPTED状态
public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW &&
              UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }
。。。
public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }
。。。
}

关闭线程池

如何停止线程,相信很多人都知道使用interrupt()或信号量来优雅停止线程,但对于多个线程,这种方式显得太过麻烦;线程线程池使用shutdown()和shutdownNow()停止线程池,其中推荐使用shutdown(),较为优雅。

shutdown

将线程状态通过CAS变成SHUTDOWN状态,并将对空闲线程调用Thread#interrupt()方法,然后调用tryTerminate()方法轮询,线程池是TIDYING或TERMINATED状态终止轮询,如果是STOP或SHUTDOWN状态(且队列是空),尝试将状态变成TIDYING->TERMINATED。

public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //安全检查,确保调用者可以执行线程池中线程的关闭
            checkShutdownAccess();
           //若线程是RUNNING,变更成SHUTDOWN状态
            advanceRunState(SHUTDOWN);
           //空闲线程调用interrupt()方法
            interruptIdleWorkers();
           //空方法,留待扩展使用
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

shutdown停止线程池还是比较优雅的,但某个任务执行时间长,很有可能使线程池无法终止(使用isTerminated()可以检查线程池是否终止),甚至死循环。

如下2种停止线程的判断:如果有任务无法执行完,case1可能死循环;case2如果没有在限定时间内停掉线程池,程序可以继续执行其他操作,即使此时线程池无法停下,这点还是比较优雅的,尤其是在顺序销毁多个资源的时候。

case1
 ExecutorService threadPool = ...
。。。
threadPool .shutdown();
while(!threadPool .isTerminated()){
  //sleep(), &etc;
}
case2
 ExecutorService threadPool = ...
。。。
threadPool .shutdown();
pool.awaitTermination(1, TimeUnit.MINUTES);

shutdownNow

将线程池变成STOP状态,对所有线程触发interrupt()方法(任务中有sleep(time),wait(),wait(time)时会发生InterruptedException,程序需要处理该异常),然后将队列中的任务移除。

不优雅:对工作线程触发Thread#interrupt(),将队列中提交的任务移除。不推荐使用,如果要使用,需要考虑任务移除影响和任务对InterruptedException的处理。

public List shutdownNow() {
        List tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            //若线程是RUNNING,SHUTDOWN,变更成STOP状态  
            advanceRunState(STOP);
            //对线程池中线程执行interrupt()
            interruptWorkers();
            //将队列中的任务全部移除
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

线程池的设定

线程池的设定有多种方案,有粗放的,也有理论可以很难实施的,也有可计算型。

但对线程池来说:

当生产能力<消费能力时,以固定的线程数(corePoolSize)运行

当生产能力>消费能力时,要增加处理的线程数到最大值(maximumPoolSize)

经过上一步后,如果生产能力下降,要将线程数重新下降到固定的数量

最佳线程数量

服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量 (CPU瓶颈类型)

粗放型

IO和CPU上考虑,是IO密集型(如http请求,数据库读写,文件读写,RPC调用等),还是CPU密集型。

IO密集型,意味着系统需要花很多时间在IO阻塞上,我们应该设置可能多的线程数,建议设置为2*CPU数。
CPU密集型务,我们应该设置数目较小的线程数,推荐使用CPU数+1(线程数目太多,线程切换所带来的开销又会对系统的响应时间带来影响)。

可计算型

进行压测,获得最大的QPS,和每个任务执行的时间。

tasks :每秒的任务数(即QPS),假设为500~1000;taskcost:每个任务花费时间,假设为0.1s;responseTime:系统允许容忍的最大响应时间,假设为1s。

corePoolSize:

吞吐量 = tasks/(1/taskcost) =taskstaskcout = (500~1000)0.1 = 50~100 个线程。corePoolSize设置应该大于50,根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可

workQueue

队列长度=(coreSizePool/taskcost)*responsetime 建议勿设置程Integer.MAX_VALUE(文中提到的流量洪峰导致超时)

maximumPoolSize

maximumPoolSize=(max(tasks)- queueCapacity)/(1/taskcost)

参考:http://www.cnblogs.com/lengender-12/p/6869554.html
http://www.cnblogs.com/waytobestcoder/p/5323130.html

你可能感兴趣的:(ThreadPoolExecutor解读笔记)