Java并发学习(二十九)-ThreadPoolExecutor及相关类学习与分析

更新2018年3月5日,把keepAliveTime相关问题解决~
线程池还是很重要的,框架中或者其他应用上,都用的比较多,以前写过一片低配线程池:简单的线程池技术写法及要点
看完线程池后,才发现远比当时想得多得多。

首先来看ThreadPoolExecutor的一个简单例子:

public class ThreadPoolTest {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);         //核心线程为5
        for (int i = 0; i < 10; i++) {          //一共加入了10个线程。
            Runnable worker = new WorkerThread("" + i);
            executor.execute(worker);
        }
        executor.shutdown();              //不接受新任务
        while (!executor.isTerminated()) {    //阻塞,直到进入terminated状态
        }
        System.out.println("Finished all threads");
    }

}

class WorkerThread implements Runnable {
    private String text;
    public WorkerThread(String s) {
        this.text = s;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()
                + " Start. text = " + text);
        processDo();
        System.out.println(Thread.currentThread().getName() + " End.");
    }
    private void processDo() {
        try {
            Thread.sleep(5000);   //假装耗时5秒钟
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public String toString() {
        return this.text;
    }
}

上述代码输出结果为:
这里写图片描述

其中,选中的5行是先输出来的,5s后,其他的再输出来,最后再过5s,最后6行输出。
为什么会有这样的结果呢?这里先说出几个点,具体原因通过分析ThreadPoolExecutor源码给出。

  • 只有5个核心线程,但有10个待运行的工作线程
  • 线程池为newFixedThreadPool产生
  • 最后一行Finished all threads 是要等到terminated状态后才输出

What is ThreadPoolExecutor

关于什么是线程池,这里就不多解释,和数据库连接池差不多的意义,先看看它的类继承关系:
这里写图片描述

先看看依次看看涉及到的几个类。

Executor

这是个接口,里面只有一个方法execute:

public interface Executor {
    /**
     * 执行器。
     */
    void execute(Runnable command);
}

ExecutorService

也是个接口,但是定义了更多个的方法,可以理解为执行服务:

public interface ExecutorService extends Executor {

    //关闭线程池,不接受新任务,但是已经接受的任务会执行完
    void shutdown();

    /*尝试停止所有正在执行的任务,停止等待任务的处理,并返回正在等待执行的任务的列表。*/
    List<Runnable> shutdownNow();

    //true如果此执行程序已关闭,则返回。
    boolean isShutdown();

    //true如果所有任务在关闭后完成,则返回。
    boolean isTerminated();

    //阻塞,直到在一个shutdown后所有的请求都执行完。或者发生超时,或者中断也退出。
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    //提交执行的返回值任务,并返回表示未完成任务结果的Future。
    <T> Future<T> submit(Callable<T> task);

    //提交一个Runnable task,并且返回一个Future。参数result,就是要返回的result。
    <T> Future<T> submit(Runnable task, T result);

    //传入task,然后返回Future,如果返回null,代表成功执行了task。
    //提交可执行任务并返回表示该任务的Future。
    Future<?> submit(Runnable task);

    //批量执行一个collection的task。 
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    /**如果执行完或者抛出错误,就返回。
     * 每一个返回的,它的Future.isDone都是返回true。
     * completed的项目可能是完成的,也可能是抛出错误的。
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    //执行给定的任务,返回一个已经成功完成的结果(即没有抛出异常),如果有的话。,返回任意一个
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    //有超时的返回任意一个。
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

AbstractExecutorService

AbstractExecutorService是ThreadPoolExecutor的上一级,主要给出了一些默认实现,实现了ExecutorService接口:

public abstract class AbstractExecutorService implements ExecutorService {
    /**
     * 返回一个FutureTask.
     * FutureTask是一个异步执行的结果。
     * runable的,
     */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

    //接受一个callable的参数。
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

    /**
     * 将task提交给submit。
     * 返回一个FutureTask。
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
    //提交一个Runnable参数
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
    //提交一个Callable参数
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

    // 有超时时间的doInvokeAny。私有的
    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)            //tasks不能为null
            throw new NullPointerException();
        int ntasks = tasks.size();
        if (ntasks == 0)             //如果没有任务,自然也不能执行
            throw new IllegalArgumentException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);       //new一个这么大的arraylist,用来存结果。
        ExecutorCompletionService<T> ecs =                //用来存放完成的异步任务。
            new ExecutorCompletionService<T>(this);       //也就是把执行器Executor传进去。

        try {
            ExecutionException ee = null;                   //如果失败,那么就记录错误。
            final long deadline = timed ? System.nanoTime() + nanos : 0L;         //超时时间
            Iterator<? extends Callable<T>> it = tasks.iterator();             //从tasks里面获得所有Callable对象。
            futures.add(ecs.submit(it.next()));        //用ecs,将iterator里面的callable提交,并把结果放到futures里面。
            --ntasks;                                   //自减数量。
            int active = 1;                            //表明处于活跃状态。
            for (;;) {                               //自旋操作。
                Future<T> f = ecs.poll();           //从ecs里面拿出一个结果。这个结果放到resultqueue里面的。
                if (f == null) {                      //f不为null,就是有结果。
                    if (ntasks > 0) {                           //再自减,加入操作。
                        --ntasks;
                        futures.add(ecs.submit(it.next()));
                        ++active;
                    }
                    else if (active == 0)       //active为0,则退出。
                        break;
                    else if (timed) {                                 //还没到时间。也就是一段时间内去取,取不到再报错。
                        f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                        if (f == null)
                            throw new TimeoutException();
                        nanos = deadline - System.nanoTime();
                    }
                    else
                        f = ecs.take();    //拿到一个结果。
                }
                if (f != null) {           //就诶过不为null。能拿到结果,就说明已经执行完了一个
                    --active;
                    try {
                        return f.get();               //返回这个future的结果。 
                    } catch (ExecutionException eex) {
                        ee = eex;
                    } catch (RuntimeException rex) {
                        ee = new ExecutionException(rex);
                    }
                }
            }
            if (ee == null)              //记录错误,然后抛出。
                ee = new ExecutionException();
            throw ee;

        } finally {
            for (int i = 0, size = futures.size(); i < size; i++)        //最后,把获取到结果的futures里面的cancel都设为true。
                futures.get(i).cancel(true);
        }
    }

    /**
     * 没有超时时间的invokeAnly
     */
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException {
        try {
            return doInvokeAny(tasks, false, 0);
        } catch (TimeoutException cannotHappen) {
            assert false;
            return null;
        }
    }

    /**
     * 有超时的invokeAny。
     */
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                           long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        return doInvokeAny(tasks, true, unit.toNanos(timeout));
    }


    /**
     * invokeAll方法。
     */
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException {
        if (tasks == null)                       //不能为null。
            throw new NullPointerException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());    //定一个一个futures
        boolean done = false;                  //定一个标志变量
        try {
            for (Callable<T> t : tasks) {            //遍历所有task,并且执行。
                RunnableFuture<T> f = newTaskFor(t);
                futures.add(f);
                execute(f);
            }
            for (int i = 0, size = futures.size(); i < size; i++) {   
             //再所有的获取一次,如果还没有完成,就尝试在进行一次get,阻塞性的等待完成。
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    try {
                        f.get();            //阻塞性等待完成。
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    }
                }
            }
            done = true;             //全部完成后,手动设置done。   此时done并不是volatile。
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);    //取消还没完成的,如果已经完成,则会取消失败。
        }
    }

    /**
     * 有超时时间的执行所有。
     * 
     * 到时间返回,或者执行完返回。
     */
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                         long timeout, TimeUnit unit)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        long nanos = unit.toNanos(timeout);
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks)
                futures.add(newTaskFor(t));

            final long deadline = System.nanoTime() + nanos;
            final int size = futures.size();

            // Interleave time checks and calls to execute in case
            // executor doesn't have any/much parallelism.
            for (int i = 0; i < size; i++) {
                execute((Runnable)futures.get(i));
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L)
                    return futures;
            }

            for (int i = 0; i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    if (nanos <= 0L)        //如果到时间了,那么直接返回。
                        return futures;
                    try {
                        f.get(nanos, TimeUnit.NANOSECONDS);
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    } catch (TimeoutException toe) {
                        return futures;
                    }
                    nanos = deadline - System.nanoTime();
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

}

ThreadPoolExecutor分析

前面花了大篇幅来列举出它的父类,当然对线程池的结构有了一定的认识,现在主要分析他的内部代码:
下面分别从其内部字段,构造方法,主要使用方法来分析线程池的内部运转流程。

主要字段

里面用一个AtomicInteger来标识状态,高三位用来标识状态,低29位用来计数。

一共有5种状态,RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED。这5种状态分别表示线程池的五种状态:

  • RUNNING:能够新建worker线程以及接受新的任务
  • SHUTDOWN:不接受新的任务,但是会把队列里已有的任务运行完
  • STOP:不接受新任务,也不运行队列里面老任务
  • TIDYING:所有任务都terminated了,并且工作线程worker的数量为0,会执行terminated()这个钩子方法
  • TERMINATED:当terminated()方法完成后就是这个状态

上述状态有以下几种转化:

  • RUNNING -> SHUTDOWN:当执行shutdown方法时候,或者jvm执行finalize时候
  • (RUNNING or SHUTDOWN) -> STOP:当执行shutdownNow的时候。
  • SHUTDOWN -> TIDYING:此时queue和pool都为空。也就是执行shutdown,然后运行完了
  • STOP -> TIDYING:STOP状态时queue已经空了,所以当pool为null时候即到达TIDYING
  • TIDYING -> TERMINATED:当terminated方法完成时候

除此之外,ThreadPoolExecutor里面有两个容易混淆的点,一个是pool,一个是queue,pool里面是指放的工作线程,
而queue里面存的是待执行任务。

//待执行任务
private final BlockingQueue<Runnable> workQueue;
//工作线程
private final HashSet<Worker> workers = new HashSet<Worker>();
Worker

这里要把Worker内部类单独提出来讲,从上面所讲的,线程池有状态,并且执行stop方法能够停止所有工作线程,就算这些线程已经在执行了,
那么有个细节,如何知道这些线程是活的并且还在执行任务呢?所以看看Worker子类的设计。

    private final class Worker extends AbstractQueuedSynchronizer implements Runnable
    {
        final Thread thread;         //worker线程,这是这worker本身这个线程
        Runnable firstTask;            //可运行的项目,即任务
        volatile long completedTasks;             //已经完成的项目。
    。。。
    }

如上所述,Worker也是一个Runnable即线程,由它来运行task,并且Worker还是个AQS,这里不懂AQS的同学可以参看以前的文章: Java并发学习(三)-AbstractQueuedSynchronizer

一开始我看了好久并不能理解为什么要继承AQS,开始的理解:
是把Worker看做一个执行器,而里面又维护这一个task队列,由分配到的Worker依次执行
后来发现理解错了,因为并没有task任务被加入到worker这个队列里面。

其实继承AQS的作用是来知道当前worker的状态,是否在执行任务,因为AQS里面维护这一个volatile类型的state,当worker执行一个任务时候会获得锁从而会改变AQS里面的state,而执行完成后会释放锁同事也会改变这个state。

所以在ThreadPoolExecutor里面,能够操作每个woker,也就能够获得相对应worker里面的state变量,从而知道worker是否在执行任务。

看看它里面一些方法:

public void lock()        { acquire(1); }     //加锁
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

以及Worker的run方法:

public void run() {
    runWorker(this);   //调用外部的runWorker方法
}

再看看外部的runWorker方法:

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();         //获得当前线程。
        Runnable task = w.firstTask;           //获取worker的firstTask
        w.firstTask = null;                    // 释放w的firstTask。
        w.unlock(); // allow interrupts             //允许中断。允许外部ThreadPoolExecutor中断它
        boolean completedAbruptly = true;                //设置completedAbruptly。
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();                    //上锁。
                if ((runStateAtLeast(ctl.get(), STOP) ||     //判断ctl的状态,并且判断两次,因为并发下。
                     (Thread.interrupted() &&              
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                     //在上锁之后,再一次检查ThreadPoolExecutor的状态是否在STOP及以上(TYDING和Terminated)
                     //如果是那么就中断
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);               //执行之前。 
                    Throwable thrown = null;                //定义个Throwable错误。
                    try {
                        task.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 {
                        afterExecute(task, thrown);                  //执行之后。
                    }
                } finally {
                    task = null;                 //释放task
                    w.completedTasks++;          //设置w的completedTask
                    w.unlock();                  //解锁。
                }
            }
            completedAbruptly = false;             //不是异常结束
        } finally {
            processWorkerExit(w, completedAbruptly);               //清理w。
        }
    }

整个执行过程还是不难理解,在运行task的run方法之前,会再一次的检验ThreadPoolExecutor的状态,如果处于STOP状态,则直接中断,并且还提供了
beforeExecute和afterExecute供子类重写,从而知道线程运行状态。

注意还有一个completedAbruptly变量,如果正常结束,则为true,否则报错则为false。

下面看看processWorkerExit方法:
这个方法主要是用来对执行完一个task的worker线程进行扫尾工作。

    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly)           //异常结束了,所以需要把这个worker清除掉
            decrementWorkerCount();      //如果中断了,那么需要减少workerCOunt。

        final ReentrantLock mainLock = this.mainLock;    //获取主要锁,因为要对workers这个set操作
        mainLock.lock();           //加锁。
        try {
            completedTaskCount += w.completedTasks;      //统计completedTask
            workers.remove(w);           //删除w。
        } finally {
            mainLock.unlock();
        }

        tryTerminate();               //当这个worker线程终止后,看是不是会进入terminated状态,也就是尽力终止。

        int c = ctl.get();             //获取ctl
        if (runStateLessThan(c, STOP)) {              //判断c是否小于stop。
            if (!completedAbruptly) {             
            //如果没有中断,即正常结束的,并且也还是running或者shutdown状态。
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;   
                     //再看看是否允许核心线程不用时候空闲
                if (min == 0 && ! workQueue.isEmpty())      //workQueue不为空,也就是还有等待执行的task任务
                    min = 1;
                if (workerCountOf(c) >= min)    //如果当前worker够用,
                    return; // replacement not needed
            }
            addWorker(null, false);            //加入一个worker。
        }
    }

processWorkerExit方法意思也比较好理解,它分为两种情况,由completedAbruptly决定,如果completedAbruptly为true,就说明是抛出异常结束的,那么就要从set里面加锁清除这个worker,并且执行完后,调用tryTerminate方法,看由于删除了这个出错的worker从而会进入terminated状态。
另外,执行完tryTerminate方法后,再次检验ctl,根据wokerQueue以及corePoolSize大小等,判断是否需要加入一个worker。

再看看tryTerminate方法:
因为当减少一个worker时候,由上面所说的状态terminated状态,可能会是最后一个worker执行完最后一个task,所以需要检验一下。

   final void tryTerminate() {
        for (;;) {
            int c = ctl.get();         //获得状态
            if (isRunning(c) ||                 //如果处于RUNNING状态
                runStateAtLeast(c, TIDYING) ||         //不是在TIDYING状态
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))    
                //处于SHUTDOWN状态但是workQueue不为null
                //以上三个说明不是要到terminated这一步,所以直接返回
                return;
            if (workerCountOf(c) != 0) {             
             // 事实说明是terminated状态,但是worker不为0,所以要清除它
                interruptIdleWorkers(ONLY_ONE);       
                //终止workers。所有。但是ONLY_ONE默认为true,所以事实上只中断一个
                //或者说只剩下一个了。
                return;
            }

            final ReentrantLock mainLock = this.mainLock;   
            mainLock.lock();                      //加锁,
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {   //更改ctl。
                    try {
                        terminated();             //当terminated时候,执行这个方法,供子类实现
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));       //最后设置ctl为terminated。
                        termination.signalAll();            //跟所有人说已经没有线程了。
                    }
                    return;
                }
            } finally {
                mainLock.unlock();          //解锁。
            }
        }
    }

由上面的分析,tryTerminate主要就是验证是否整个ThreadPoolExecutor是否处于了TERMINATED状态,最后如果确认将处于TERMINATED状态,那么执行terminated方法,并且设置ctl为TERMINATED。

再看看interruptIdleWorkers方法,当确认所有worker执行完了,那么并且要处于TERMINATED状态时候,那么就会执行这个方法把所有worker都终止:

    private void interruptIdleWorkers(boolean onlyOne) {   //onlyOne默认传入的为true
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();                    //需要加锁。
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();        //中断worker线程。
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)       //只中断一个,那就退出吧。默认是中断一个
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

从上面分析Worker类的run方法,从而把整个run方法的执行流程都走了一遍,整理一遍,

  1. Worker的run方法
  2. 外部的runWorker(this)方法
  3. 执行完之后的清理processWorkerExit方法
  4. 判断是否要处于TERMINATED状态的tryTerminated方法
  5. 如果4成立,则可能需要interruptIdleWorkers进行清理。
构造方法

ThreadPoolExecutor给外部提供了几个构造方法,主要是初始化几个重要参数,如果没有给出,则会是默认的情况:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

其他几个构造方法就不列出,这里看看这些参数的意思:

参数名作用
corePoolSize核心线程池大小
maximumPoolSize最大线程池大小
keepAliveTime线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
TimeUnitkeepAliveTime时间单位
workQueue阻塞任务队列
threadFactory新建线程工厂
RejectedExecutionHandler当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理

有两种关系一个是corePoolSize,maximumPoolSize,workQueue之间关系:

  • 当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中可能存在空闲线程。
  • 当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 。
  • 当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务 。
  • 当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理 。

另一方面,corePoolSize和keepAliveTime关系:

  • 当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
  • 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭 ,而不比等到
    有corePoolSize这么多。
默认的线程池配置方案

当然对于一些情况来说,只使用Executors类提供的默认配置方案就可以了有以下几种配置:

  1. newFixedThreadPool
    看方法具体内容:
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

选择一定数量的初始线程nThreads,同时corePoolSize与maximumPoolSize大小相同,并且使用了一个无界的LinkedBlockingQueue作为task队列,这样以来,当线程池里面线程都工作时,再接受无论多少线程都会放入LinkedBlockingQueue中,而不会丢弃。
关于LinkedBlockingQueue可以看:Java并发学习(二十三)-LinkedBlockingQueue和LinkedBlockingDeque分析

  1. newCachedThreadPool
    看具体内容:
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

构造一个缓冲功能的线程池,corePoolSIze为0,而maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,同时用来存储task的队列为SynchronousQueue,而对于SynchronousQueue是没有容量的,所以它不具有存储task功能,一旦有多余task任务,就会新建一个worker去解决,同时一旦超过60s,空闲的worker线程就会被回收。
关于SynchronousQueue可以看:Java并发学习(二十六)-Java中SynchronousQueue分析

  1. newSingleThreadExecutor
    只支持一个线程的线程池:
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

从上面可以看出,corePoolSize和maximumPoolSize都为1,并且task的queue为LinkedBlockingQueue,这样以来,保证任务不会丢失,而是会一个个串行执行。

  1. newScheduledThreadPool
    一个具有定时功能的线程池
public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }

//调用
 public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

从而,newScheduledThreadPool实际上也是一个ThreadPoolExecutor,并且给出了一个corePoolSize,而maximumPoolSize=Integer.MAX_VALUE,task的queue为DelayedWorkQueue。
由于DelayedWorkQueue是无界队列,所以maximumPoolSize=Integer.MAX_VALUE这个值其实没有任何意义,因为DelayedWorkQueue可以一直装而不必考虑是否装满了。

下面看看ThreadPool的一些主要方法,从而理解整个ThreadPoolExecutor的流程,以及corePoolSize,maximumPoolSize,workQueue关系由来。

execute方法

由最开始那个例子可以知道,当往线程池里面丢入待执行任务时,使用execute方法:

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();                 //获取ctl。
        if (workerCountOf(c) < corePoolSize) {      //看c的大小是否大道corePoolSize。
            if (addWorker(command, true))            //小于就直接往里面加不用等。
                return;
            c = ctl.get();
        }
        //以下说明大于corePoolSize
        //这个就需要排队等待。
        if (isRunning(c) && workQueue.offer(command)) {    //处于running状态,并且加入coommand成功。
            int recheck = ctl.get();          //用于重新检查一遍。
            if (! isRunning(recheck) && remove(command))    //短路与,如果不在running状态,那么就取出command。
                reject(command);
            else if (workerCountOf(recheck) == 0)    //为0则直接添加即可。
                addWorker(null, false);
        }
        else if (!addWorker(command, false))     //如果此时有并发,导致不需要排队等待,则尝试添加。
            reject(command);
    }

通过让ctl和corePoolSize对比,从而决定是否需要新增加worker。
接下来看addWorker方法:

addWorker方法

当往线程池中加入新的一个线程时候就会调用addWorker方法:

    private boolean addWorker(Runnable firstTask, boolean core) {
        //以下为判断状态并且尝试更改ctl的值。
        retry:
        for (;;) {                       //自旋。
            int c = ctl.get();              //获得ctl
            int rs = runStateOf(c);             //获得状态。

            if (rs >= SHUTDOWN &&                           //如果处于SHUTDOWN或者以上
                ! (rs == SHUTDOWN &&                         
                   firstTask == null &&
                   ! workQueue.isEmpty()))              
                    //处于SHUTDOWN状态,而firstTask为null,但是workQueue不为空,所以此时也不能加新线程
                return false;
            for (;;) {                                       //自旋。
                int wc = workerCountOf(c);                 //获得worker的count。
                if (wc >= CAPACITY ||                      //超过容量了。
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))     //增加c的workcount的值。
                    break retry;
                c = ctl.get();  // Re-read ctl             重新读ctl的值。
                if (runStateOf(c) != rs)                 //如果状态改变了,则重新来。
                    continue retry;
            }
        }

        //以下为初始化一个worker。
        boolean workerStarted = false;                   
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);                   //new一个worker。把firstTask放进去。
            final Thread t = w.thread;                         //获得thread。
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();                //加锁。
                try {
                    int rs = runStateOf(ctl.get());         //读取ctl的状态。
                    if (rs < SHUTDOWN ||                                  //处于running状态。
                        (rs == SHUTDOWN && firstTask == null)) {         
                         //是shutdown状态,但是firstTask为null。
                        if (t.isAlive())                   //判断t是否为可以启动的。
                            throw new IllegalThreadStateException();
                        workers.add(w);                             //把w加入到workers。
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;                 //更改largestPoolSize的值。
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {         //如果已经加进去了,那么就启动。
                    t.start();              //运行线程
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)                    //加入失败。
                addWorkerFailed(w);
        }
        return workerStarted;          //返回这个状态。
    }

addWorker方法主要分为两个步骤,一个是尝试更改ctl,其次是往set里面增加一个worker。如果增加成功,则会将该线程启动,
而一旦该线程启动,task里面的run方法就会被运行,从而执行了这个任务。

shutdown方法

执行完shutdown方法后,不会增加新的任务,但是会把老任务执行完。

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;     //final变量。
        mainLock.lock();            //加锁。
        try {
            checkShutdownAccess();           //判断能否进入。
            advanceRunState(SHUTDOWN);          //把状态改为SHUTDOWN
            interruptIdleWorkers();     //中断workers
            onShutdown(); // hook for ScheduledThreadPoolExecutor执行监听方法,公子类重写。
        } finally {
            mainLock.unlock();         
        }
        tryTerminate();
    }

再看interruptIdleWorker方法:

 private void interruptIdleWorkers() {
        interruptIdleWorkers(false);
    }

前面说过interruptIdleWorkers方法,前面是传入true,这个是传入false,也就是不满足要求的worker都会被回收,而由于Worker继承子AQS,所以在interruptIdleWorkers通过判断其state变量验证它是否在处理任务,没有处理则会回收。

!t.isInterrupted() && w.tryLock()
shutdownNow方法

中断当前的执行的线程,并且把这些线程返回回来。

    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();              //加锁。
        try {
            checkShutdownAccess();        //判断是否能如
            advanceRunState(STOP);       //更改状态。
            interruptWorkers();          //中断所有
            tasks = drainQueue();       //返回所有已执行的线程
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

看看drainQueue方法:

    private List<Runnable> drainQueue() {
        BlockingQueue<Runnable> q = workQueue;             //获取workQueue,待工作队列。
        ArrayList<Runnable> taskList = new ArrayList<Runnable>();
        q.drainTo(taskList);
        if (!q.isEmpty()) {
            for (Runnable r : q.toArray(new Runnable[0])) {
                if (q.remove(r))
                    taskList.add(r);
            }
        }
        return taskList;
    }

drainQueue方法,就是把workQueue里面数据包装成一个List返回。

getTask方法

从workQueue里面返回一个任务。

    private Runnable getTask() {
        boolean timedOut = false;               // 没有超时
        for (;;) {
            int c = ctl.get();                   //获取ctl
            int rs = runStateOf(c);              //获取c的状态。
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();           //如果已经shutdown了或者为empty,则需要减少。并且直接返回null
                return null;
            }
            int wc = workerCountOf(c);           //获取workerCount。
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;      //看允许超时
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {             //判断是否需要自减c
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :        //出队一个r
                    workQueue.take();
                if (r != null)
                    return r;     //返回。
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

每次设置参数,都会调用interruptIdleWorkers方法,把空闲的线程都回收。

关于keepAliveTime的用法探究

前天开始写这个问题时候,留了个问题,就是keepAliveTime在哪里,怎么使用,花了点时间把他解决了。
全局搜keepAliveTime,除了构造方法,就只有getTask 里面用到了,而且是从workQueue里面去获得task时候。这个workQueue我们知道是task任务队列。如下这一行:

Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :        //出队一个r
                    workQueue.take();

而timed就是是否从核心线程中回收,代码如下:

boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;      //看回收线程是否需要回收核心线程

再看看哪里调用getTask方法:
runWorker里面会调用getTask方法,关于runWorker文章前面已经分析过:

while (task != null || (task = getTask()) != null)

runWorker传入了一个Worker w的参数,如果task为null,并且没有获取到task(如果超时也将为null),那么直接将不执行这个循环。
在runWorker方法里面,我们知道最后都会调用清理方法,并且completedAbruptly值为false:

processWorkerExit(w, completedAbruptly);               //清理w。

最后,会将该w删除,最后会判断是否需要加入一个非核心线程。
这样,当一定时间keepAliveTime获取不到task任务时候,该worker就会被删除,也就完成了线程池的清理。

execute方法执行过程

还有一个关于线程池execute方法执行过程的流程分析:
由前文的解释,当还没有达到corePoolSize线程数量时,会执行addWorker(command, true) 方法。
再看addWorker方法:
里面会先new一个worker,new Worker(firstTask);
看看Woker的构造方法:

        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;                //firstTask,第一个任务。
            this.thread = getThreadFactory().newThread(this);       //一个新线程,为当前worker。
        }

其次,会获得该worker的t ,t是什么呢?t就是当前worker的线程,或者说是该线程的一个引用。
最后,如果worker加入成功,则会执行t.start运行该worker:

if (workerAdded) {         //如果已经加进去了,那么就启动task线程。
                    t.start();
                    workerStarted = true;
                }

而该worker的run方法,就是调用外部的runWorker(this)方法,至此,一切都通了。

尾声

分析过程中,我发现了一个和传统不同的观点,就是线程池的线程复用性,在runWorker 方法里,无论这个worker执行成功还是失败,
都会调用processWorkerExit这个清理方法,而这个清理方法,总是会把传入的这个worker清理掉,然后看情况是否需要生成一个非核心
线程。所以其实这里并不存在线程的复用性~~

如果哪里分析有问题,还请指出~

参考文章

  1. https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html
  2. https://www.jianshu.com/p/ae67972d1156
  3. https://www.jianshu.com/p/d2729853c4da
  4. https://www.cnblogs.com/zedosu/p/6665306.html
  5. http://blog.csdn.net/xiaoxufox/article/details/52278508
  6. http://blog.csdn.net/qq_25806863/article/details/71126867
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值