线程池ThreadPoolExecutor源码解析

ExecutorService接口定义

 在解读ThreadPoolExecutor源码之前,先解读关于线程池实现底层定义的的接口ExecutorService,定义了一些方法管理任务中止或者返回一个Future用以获取一个或者多个异步任务的执行结果,定义的方法如下:

public interface ExecutorService extends Executor {
    //平滑的关闭ExecutorService,当此方法被调用时,
    //ExecutorService停止接收新的任务并且等待已经提交的任务(包含提交正在执行和提交未执行)执行完成。
    //当所有提交任务执行完毕,线程池即被关闭。
    void shutdown();
     //停止所有已经提交的在执行中的任务,正在等待执行的任务,返回所有等待被执行的任务的list
    List<Runnable> shutdownNow
    //一个任务是否已被终止
    boolean isShutdown();
     //所有的任务是否已经被终止
    boolean isTerminated();
    //接收人timeout和TimeUnit两个参数,用于设定超时时间及单位。
    //当等待超过设定时间时,会监测ExecutorService是否已经关闭,
    //若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用。
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);
     //执行列表中的任务,返回任务执行结果和状态
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
    //超过时限后,任何尚未完成的任务都会被取消。
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
        throws InterruptedException;

     //执行提交的task集合,返回一个task成功执行后的结果,而其他没有执行完成的task将被取消 
     //如果提交的任务列表中,没有1个正常完成的任务,
     //那么调用invokeAny会抛异常,究竟抛的是哪儿个任务的异常,无关紧要。
     //invokeAny()和任务的提交顺序无关,只是返回最早正常执行完成的任务。

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    //如果在超时之前,所有任务已经都是异常终止,那就没有必要在等下去了;
    //如果超时之后,仍然有正在运行或等待运行的任务,那么会抛出TimeoutException。
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ExecutorService接口抽象实现AbstractExecutorService

 下面看ExecutorService的抽象实现AbstractExecutorService,AbstractExecutorService源码分析如下:

public abstract class AbstractExecutorService implements ExecutorService {

    //对于给定的runnable和默认的value,返回一个RunnableFuture对象
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

    //对于给定的Callable型任务,返回一个RunnableFuture对象
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

    //往线程池提交Runnable型任务
    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;
    }
}

 核心方法返回某个异步任务的执行结果实现如下:

   // invokeAny核心实现过程,获取某个任务的执行结果
    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)
            throw new NullPointerException();
        int ntasks = tasks.size();
        if (ntasks == 0)
            throw new IllegalArgumentException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        //ecs解耦了获取新的异步任务执行结果,这些异步任务来源于获取完已经成的任务的执行结果
        ExecutorCompletionService<T> ecs =
            new ExecutorCompletionService<T>(this);

         //为了效率,特别是在执行器并行度有限的情况下,在提交新的任务之前需要检查之前提交的任务是否已经完成,
         // 为主循环的混乱负责,这种交互增加了异常机制,
        try {
            ExecutionException ee = null;
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            Iterator<? extends Callable<T>> it = tasks.iterator();
            //先开始提交一个任务,其余的依次提交
            futures.add(ecs.submit(it.next()));
            // 提交一个任务之后,任务数量减1
            --ntasks;
            int active = 1;
            //死循环遍历
            for (;;) {
                //任务执行结果在队列中,任务执行结果Future结果队列
                Future<T> f = ecs.poll();
                if (f == null) {
                    if (ntasks > 0) {
                        --ntasks;
                        //提交任务
                        futures.add(ecs.submit(it.next()));
                        //活跃任务数加1
                        ++active;
                    }
                    else if (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,任务执行结束,活跃任务数减1
                    --active;
                    try {
                        //返回执行结果
                        return f.get();
                    } 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.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();

            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

ThreadPoolExecutor线程池的重要参数

  1. corePoolSize:核心线程数
    • 核心线程会一直存活,即使没有任务需要执行
    • 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
    • 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
  2. queueCapacity:任务队列容量(阻塞队列)
    • 当核心线程数达到最大时,新任务会放在队列中排队等待执行
  3. maxPoolSize:最大线程数
    • 当线程数>=corePoolSize,且任务队列未满时。线程池会创建新线程来处理任务
    • 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
  4. keepAliveTime:线程空闲时间
    • 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
    • 如果allowCoreThreadTimeout=true,则会直到线程数量=0
  5. allowCoreThreadTimeout:允许核心线程超时
  6. rejectedExecutionHandler:任务拒绝处理器
     两种情况会拒绝处理任务:
     当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
     当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown.如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务
    • 线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常
    • ThreadPoolExecutor类有几个内部实现类来处理这类情况:
       AbortPolicy 丢弃任务,抛运行时异常
       CallerRunsPolicy 执行任务
       DiscardPolicy 忽视,什么都不会发生
       DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
       实现RejectedExecutionHandler接口,可自定义处理器

ThreadPoolExecutor线程池的五种状态

  1. Running可以接受新任务,同时也可以处理阻塞队列里面的任务;
  2. Shutdown不可以接受新任务,但是可以处理阻塞队列里面的任务;
  3. Stop不可以接受新任务,也不处理阻塞队列里面的任务,同时还中断正在处理的任务;
  4. Tidying属于过渡阶段,在这个阶段表示所有的任务已经执行结束了,当前线程池中是不存在有效的线程的,并且将要调用terminated方法;
  5. Terminated终止状态,这个状态是在调用完terminated方法之后所处的状态;

ThreadPoolExecutor线程池的执行顺序

 线程池按以下行为执行任务

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满:
    • 若线程数小于最大线程数,创建线程
    • 若线程数等于最大线程数,抛出异常,拒绝任务

ThreadPoolExecutor任务执行过程源码分析

 执行任务execute方法分析如下:

//提交任务command执行,如果command被关闭或者线程池容量满了,将对command执行拒绝处理
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();

        int c = ctl.get();
        //统计有效线程数,如果小于核心池大小,创建新的线程
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            //recheck防止线程池状态的突变,如果突变,那么将reject线程,防止workQueue中增加新线程
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                //上下两个操作都有addWorker的操作,但是如果在workQueue.offer的时候Worker变为0,
                //那么将没有Worker执行新的task,所以增加一个Worker.
                addWorker(null, false);
        }
        //如果workQueue满了,那么这时候可能还没到线程池的maxnum,所以尝试增加一个Worker
        else if (!addWorker(command, false))
            //如果Worker数量到达上限,那么就拒绝此线程
            reject(command);
    }

 其中方法执行反复多次调用addWorker操作,addWorker核心执行逻辑如下:
 判断线程池状态–>创建wokrer–>recheck线程池状态–>创建worker–>添加worker–>启动worker

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

            //rs >= SHUTDOWN
            //判断当前线程池的状态是不是已经shutdown,如果shutdown了拒绝线程加入

            //(rs!=SHUTDOWN || first!=null || workQueue.isEmpty())
            //如果rs不为SHUTDOWN,此时状态是STOP、TIDYING或TERMINATED,所以此时要拒绝请求
            //如果此时状态为SHUTDOWN,而传入一个不为null的线程,那么需要拒绝
            //如果状态为SHUTDOWN,同时队列中已经没任务了,那么拒绝掉

            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                //如果当前的数量超过了CAPACITY,或者超过了corePoolSize和maximumPoolSize(试core而定)
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //CAS尝试增加线程数,如果失败,证明有竞争,那么重新到retry。
                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
            }
        }

        //执行添加worker并启动worker逻辑
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {

                    int rs = runStateOf(ctl.get());
                    //重新检测线程池状态和待添加的线程是否还活着
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        //添加成功,修改当前最大线程数量
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                //尝试启动线程执行
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                //线程启动失败的时候,需要remove
                addWorkerFailed(w);
        }
        return workerStarted;
    }

 线程池还有很多其它逻辑与状态转换,这次分析就到这,后续逻辑以后再梳理。

猜你喜欢

转载自blog.csdn.net/Pengjx2014/article/details/81464026