ThreadPoolExecutor分析

线程池由于减少了每个任务调用的开销, 它们通常可以在执行大量异步任务时提供增强的性能, 并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法.

1. ThreadPoolExecutor

1.1 构造函数

public class ThreadPoolExecutor extends AbstractExecutorService {
    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;
    }
}

首先看下ThreadPoolExecutor的构造函数中各个参数的意义.

  1. corePoolSize: 核心线程数量. 当线程数少于corePoolSize的时候, 直接创建新的线程, 即便其他线程是空闲的. 当线程池中的线程数目达到corePoolSize后, 就会把到达的任务放到缓存队列当中.

  2. maximumPoolSize: 线程池最大线程数. 如果线程数量少于线程最大数且大于核心线程数量的时候, 只有当阻塞队列满了才创建新线程. 当线程数量大于最大线程数且阻塞队列满了这时候就会执行一些策略来响应该线程.

  3. keepAliveTime: 线程没有任务执行最多保持多久时间终止. 也就是当线程数量超过核心线程数量的时候, 且小于最大线程数量, 这一部分的线程在没有任务执行的时候是会保持直到超过keepAliveTime才会销毁

  4. unit: keepAliveTime的时间单位.

  5. workQueue: 阻塞队列, 存储等待执行的任务, 会对线程池的运行产生很大的影响. 当提交一个新的任务到线程池的时候, 线程池会根据当前线程数量来选择不同的处理方式

    • ArrayBlockingQueue: 基于数组的有界阻塞队列, 任务以FIFO顺序排序.
    • LinkedBlockingQueue: 基于链表的阻塞队列, 任务以FIFO顺序排列, 吞吐量优于ArrayBlockingQueue, 在使用时需要注意, 此阻塞队列在不设置大小的时候, 默认的长度是Integer.MAX_VALUE.
    • PriorityBlockingQueue: 类似于LinkedBlockQueue, 但其所含任务的排序不是FIFO, 而是依据任务的自然排序顺序或者是构造函数的Comparator决定的顺序.
    • SynchronousQueue: 特殊的BlockingQueue, 对其的操作必须是放和取交替完成的, 典型的生产者-消费者模型, 它不存储元素, 每一次的插入必须要等另一个线程的移除操作完成.
  6. threadFactory: 线程工厂, 用来创建线程, 当使用默认的线程工厂创建线程的时候, 会使得线程具有相同优先级, 并且设置了守护性, 同时也设置线程名称

  7. handler: 拒绝策略, 当workQueue满了, 并且没有空闲的线程数, 即线程达到最大线程数, 就会有四种不同策略来处理.

    • AbortPolicy: 拒绝提交, 直接抛出异常, 也是默认的饱和策略.
    • CallerRunsPolicy: 线程池还未关闭时, 用调用者的线程执行任务.
    • DiscardPolicy: 丢掉提交任务.
    • DiscardOldestPolicy: 线程池还未关闭时, 丢掉阻塞队列最久为处理的任务, 并且执行当前任务.

线程池的主要结构

线程池中 核心线程、线程队列、最大线程的运行准则:

  1. 首先可以通过线程池提供的submit()方法或者execute()方法, 要求线程池执行某个任务. 线程池收到这个要求执行的任务后, 会有几种处理情况.
    • 如果当前线程池中运行的线程数量还没有达到corePoolSize大小时, 线程池会创建一个新的线程运行你的任务, 无论之前已经创建的线程是否处于空闲状态.
    • 如果当前线程池中运行的线程数量已经达到设置的corePoolSize大小, 线程池会把你的这个任务加入到等待队列中. 直到某一个的线程空闲了, 线程池会根据设置的等待队列规则, 从队列中取出一个新的任务执行.
    • 如果根据队列规则, 这个任务无法加入等待队列. 这时线程池就会创建一个“非核心线程”直接运行这个任务. 注意, 如果这种情况下任务执行成功, 那么当前线程池中的线程数量一定大于corePoolSize.
    • 如果这个任务无法被“核心线程”直接执行, 又无法加入等待队列, 又无法创建“非核心线程”直接执行, 且你没有为线程池设置RejectedExecutionHandler. 这时线程池会抛出RejectedExecutionException异常, 即线程池拒绝接受这个任务. (实际上抛出RejectedExecutionException异常的操作, 是ThreadPoolExecutor线程池中一个默认的RejectedExecutionHandler实现: AbortPolicy)
  2. 一旦线程池中某个线程完成了任务的执行, 它就会试图到任务等待队列中拿去下一个等待任务(所有的等待任务都实现了BlockingQueue接口, 按照接口字面上的理解, 这是一个可阻塞的队列接口), 它会调用等待队列的poll()方法, 并停留在哪里.
  3. 当线程池中的线程超过你设置的corePoolSize参数, 说明当前线程池中有所谓的“非核心线程”. 那么当某个线程处理完任务后, 如果等待keepAliveTime时间后仍然没有新的任务分配给它, 那么这个线程将会被回收. 线程池回收线程时, 对所谓的“核心线程”和“非核心线程”是一视同仁的, 直到线程池中线程的数量等于你设置的corePoolSize参数时, 回收过程才会停止.

1.2 线程池的5种状态

public class ThreadPoolExecutor extends AbstractExecutorService {
    
    // ctl是控制线程的状态的, 里面包含两个状态, 线程的数量和线程池运行的状态. 
    // 高3位是用来保存线程池运行的状态的, 低29位用于保存线程的数量, 这里的限制是2^29-1, 大约有5亿3千6百万左右. 
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    // COUNT_BITS = 29, 用于位于操作
    private static final int COUNT_BITS = Integer.SIZE - 3;
    // 2^29-1 = 536,870,911, 线程的容量
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
    
    // runState is stored in the high-order bits
    // 高3位: 111, 接受新任务并且继续处理阻塞队列中的任务
    private static final int RUNNING    = -1 << COUNT_BITS;
    // 高3位: 000, 不接受新任务但是会继续处理阻塞队列中的任务
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    // 高3位: 001, 不接受新任务, 不在执行阻塞队列中的任务, 中断正在执行的任务
    private static final int STOP       =  1 << COUNT_BITS;
    // 高3位: 010, 所有任务都已经完成, 线程数都被回收, 线程会转到TIDYING状态会继续执行钩子方法
    private static final int TIDYING    =  2 << COUNT_BITS;
    // 高3位: 110, 钩子方法执行完毕
    private static final int TERMINATED =  3 << COUNT_BITS;
    
    // 用于打包ctl或者拆包ctl的, 如果你源码看得比较多, 这种操作应该是经常看到的
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }
}
  1. RUNNING: 在这个状态的线程池能判断接受新提交的任务, 并且也能处理阻塞队列中的任务
  2. SHUTDOWN: 处于关闭的状态, 该线程池不能接受新提交的任务, 但是可以处理阻塞队列中已经保存的任务, 在线程处于RUNNING状态, 调用shutdown()方法能切换为该状态.
  3. STOP: 线程池处于该状态时既不能接受新的任务也不能处理阻塞队列中的任务, 并且能中断现在线程中的任务. 当线程处于RUNNING和SHUTDOWN状态, 调用shutdownNow()方法就可以使线程变为该状态
  4. TIDYING: 在SHUTDOWN状态下阻塞队列为空, 且线程中的工作线程数量为0就会进入该状态, 当在STOP状态下时, 只要线程中的工作线程数量为0就会进入该状态.
  5. TERMINATED: 在TIDYING状态下调用terminated()方法就会进入该状态. 可以认为该状态是最终的终止状态.

2. execute方法

了解ThreadPoolExecutor的构造函数和5种状态之后, 看下如何提交一个任务. 一般情况下, 我们可以调用submit和execute方法提交一个任务至线程池, 其中submit方法最终调用了execute方法, 此处暂且不表. 我们先来看下execute方法内部如何实现.

public class ThreadPoolExecutor extends AbstractExecutorService {
    // 默认为false, 用于控制核心线程在空闲状态是否会被回收. 
    private volatile boolean allowCoreThreadTimeOut;
    // 用于记录最大的工作线程池的工作线程的大小.
    private int largestPoolSize;
    // 统计线程池完成的任务数量
    private long completedTaskCount;
    
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        
        // 1. 如果当前运行的线程数小于corePoolSize, 则马上尝试使用command对象创建一个新线程. 
        // 调用addWorker()方法进行原子性检查runState和workerCount, 然后通过返回false来防
        // 止在不应该添加线程时添加了线程产生的错误警告.
        
        // 2. 如果一个任务能成功添加到任务队列, 在我们添加一个新的线程时仍然需要进行双重检查(因为自上一次检查后, 
        // 可能线程池中的其它线程全部都被回收了)或者在进入此方法后, 线程池已经shutdown了. 所以我们必须重新检查
        // 状态, 如果有必要, 就在线程池shutdown时采取回滚入队操作移除任务, 如果线程池的工作线程数为0, 就启动新的线程. 
        
        // 3. 如果任务不能入队, 那么需要尝试添加一个新的线程, 但如果这个操作失败了, 那么我们知道线程池可能
        // 已经shutdown了或者已经饱和了, 从而拒绝任务. 
        int c = ctl.get();
        // 通过workerCountOf方法计算当前线程的线程数
        if (workerCountOf(c) < corePoolSize) {
            // 如果小于corePoolSize, 执行addWorker方法创建新的线程执行任务
            if (addWorker(command, true))
                return; 
            // 如果添加线程失败了, 就再次获取线程池控制状态
            c = ctl.get();
        }
        // 如果线程池处于RUNNING状态, 则尝试把任务添加到任务队列
        if (isRunning(c) && workQueue.offer(command)) { // 此处添加队列失败说明队列已满, 尝试新加线程执行
            int recheck = ctl.get();
            // 如果线程池已经不是RUNNING状态了, 把任务从队列中移除, 并执行拒绝任务策略「可能线程池已经被关闭了」
            if (!isRunning(recheck) && remove(command)) {
                reject(command);
            } else if (workerCountOf(recheck) == 0) {
                //如果工作线程数为0, 就添加一个新的工作线程, 「因为旧线程可能已经被回收了, 所以工作线程数可能为0」 
                addWorker(null, false);
            }
        } else if (!addWorker(command, false)) { // 此处添加线程失败说明当前线程池已经到了极限.
            reject(command); // 执行addWork失败, 执行reject方法处理该任务. 
        }
    }
}

线程池中大致的机制是这样的:

  1. 如果正在运行的线程数 < coreSize, 马上创建线程执行该task, 不排队等待.
  2. 如果正在运行的线程数 >= coreSize, 把该task放入队列.
  3. 如果队列已满 && 正在运行的线程数 < maximumPoolSize, 创建新的线程执行该task.
  4. 如果队列已满 && 正在运行的线程数 >= maximumPoolSize, 线程池调用handler的reject方法拒绝本次提交.

2.1 addWorker

在execute方法中可以看到, addWorker是创建新的线程并执行任务的关键方法, 继续查看其内部实现.

public class ThreadPoolExecutor extends AbstractExecutorService {
    
    private final HashSet<Worker> workers = new HashSet<Worker>();
    
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // 首先判断当前线程的状态是否符合条件, 不符合条件则不做处理直接返回.
            if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                // 通过参数core判断当前线程是否为核心线程, 需要 >= 核心线程还是最大线程
                if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
                    return false; // 返回不能新增线程
                    // 如果cas执行 [工作线程数 + 1] 成功, 跳出循环.
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs) 
                    continue retry; // 如果线程池的状态发生改变了, 再次重复大循环
            }
        }
        
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null; // Worker包装了线程和任务
        try {
            w = new Worker(firstTask); // 创建一个新的worker
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    int rs = runStateOf(ctl.get()); // 拿着锁重新检查池程池的状
                    // 线程池的状态为RUNNING || !(线程池的状态SHUTDOWN并且提交的任务为null时)
                    if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) 
                            throw new IllegalThreadStateException();
                        workers.add(w); // 将worker添加入HashSet中
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s; // 主要是用于记录最大线程数.
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start(); // 添加成功后, 直接启动线程执行任务
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
}

addWorker方法一共有4种调用方式

  1. addWorker(command, true): 线程数 < coreSize时, 将task放入workers, 如果线程数 >= coreSize, 返回false.
  2. addWorker(command, false): 当阻塞对列已满, 尝试将新的task放入workers, 如果线程数 >= maximumPoolSize, 返回false.
  3. addWorker(null, false): 放入一个空的task到workers, 此时线程数的限制是maximumPoolSize, 相当于创建一个新的线程, 没立马分配任务.
  4. addWorker(null, true): 放入一个空的task到workers, 线程数 < coreSize. 实际的使用是在prestartCoreThread()等方法.

2.2 runWorker

内部类Worker继承自AbstractQueuedSynchronizer, 实现了Runnable接口. 其中run方法实际上调用ThreadPoolExecutor的runWorker方法.

private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
    final Thread thread;
    Runnable firstTask;
    volatile long completedTasks;
    
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
    
    public void run() {
        runWorker(this);
    }
}
public class ThreadPoolExecutor extends AbstractExecutorService {
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread(); // 获取当前线程(和worker绑定的线程)
        Runnable task = w.firstTask; // 获取firstTask任务并执行
        w.firstTask = null;
        w.unlock(); // 线程启动后, 释放锁, 设AQS状态为0.
        boolean completedAbruptly = true;
        try {
            // 如果worker的firstTask为null, 调用getTask从阻塞队列获取等待任务执行. 否则, 阻塞该方法. 
            while (task != null || (task = getTask()) != null) {
                w.lock();
                if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && 
                        !wt.isInterrupted()) 
                    wt.interrupt();
                try {
                    // 执行任务前后可定制的beforeExecute和afterExecute方法
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        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方法
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }
}

runWorker()方法除了会运行我们提交的任务外, 还会自动取出从任务队列中的任务, 与此同时还提供了任务执行之前和任务执行之后的钩子方法, 并且提供了所有任务都执行完的钩子方法. 通过这些钩子方法, 我们就可以做我们的一些处理操作了.

2.3 getTask

public class ThreadPoolExecutor extends AbstractExecutorService {
    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            // 必要情况下需要检查workQueue是否为空
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
            int wc = workerCountOf(c);
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            // 如果当前工作线程数 > maximumPoolSize > (1或者任务队列为空), 那么减少工作线程数, 并返回null
            // 如果当前工作线程数 > corePoolSize > (1或者任务队列为空), 且超过keepAliveTime还没有拿到任务, 那么减少工作线程数, 并返回null
            // 如果允许核心线程超时, 且超过keepAliveTime还没有拿到任务, 且当前线程数(>1或者任务队列为空), 那么减少工作线程数, 并返回null
            if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
            try {
                Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
}

总结一下getTask()方法, 首先他会不断地检查线程池的状态, 如果线程池的状态为SHUTDOWN或者STOP时, 它会直接返回null, 同时他在特定情况下会减少工作线程数, 也是返回null, 比较重要的一点是, 因为getTask()方法是从阻塞队列中获取任务的, 所以他支持有限时间的等待poll(), 和无限时间的等待take().

3. submit方法

了解execute方法之后, 我们来了解下submit方法

public abstract class AbstractExecutorService implements ExecutorService {
    public Future<?> submit(Runnable task) {
        if (task == null) 
            throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    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;
    }

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) 
            throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
    
    // RunnableFuture 是用于获取执行结果的, 我们常用它的子类 FutureTask
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
}

submit方法一共有三个重载, 主要是方法参数的不同, 由这些参数构造一个FutureTask对象, 交给Executor的execute方法执行. submit方法的关键就是构造的FutureTask对象了.

3.1 FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
    
    // NEW -> COMPLETING -> NORMAL
    // NEW -> COMPLETING -> EXCEPTIONAL
    // NEW -> CANCELLED
    // NEW -> INTERRUPTING -> INTERRUPTED
    private volatile int state;
    private static final int NEW          = 0; // 初始状态 
    private static final int COMPLETING   = 1; // 结果计算完成或响应中断到赋值给返回值之间的状态.  
    private static final int NORMAL       = 2; // 任务正常完成, 结果被set 
    private static final int EXCEPTIONAL  = 3; // 任务抛出异常 
    private static final int CANCELLED    = 4; // 任务已被取消 
    private static final int INTERRUPTING = 5; // 线程中断状态被设置true, 但线程未响应中断 
    private static final int INTERRUPTED  = 6; // 线程已被中断 
    
    private Callable<V> callable; // 将要执行的任务 
    private Object outcome; // 用于get()返回的结果, 也可能是用于get()方法抛出的异常 
    private volatile Thread runner; // 执行callable的线程, 调用FutureTask.run()方法通过CAS设置 
    private volatile WaitNode waiters; // 栈结构的等待队列, 该节点是栈中的最顶层节点.
     
    // 这部分主要用于cas相关操作 
    private static final sun.misc.Unsafe UNSAFE;
    private static final long stateOffset;
    private static final long runnerOffset;
    private static final long waitersOffset;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = FutureTask.class;
            stateOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("state"));
            runnerOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("runner"));
            waitersOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("waiters"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
    
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
}

一个异步可取消任务, FutureTask提供了Future接口的基本实现, 其中包含开始执行任务和结束任务的方法, 查询任务是否完成的方法, 或者获取任务结果的方法, 等等. 仅当任务执行完成了, 才能获取到结果. 并且调用get()方法会阻塞当前线程直到任务执行完成, 如果任务已经完成了, 不能重新开始或者取消, 除非这个任务调用了runAndReset()方法.

FutureTask可以包装一个Callable或者是Runnable, 因为FutureTask实现了Runnable对象(Callable接口类似于Runnable, Callable相对于Runnable来说, 仅仅多了一个返回值和Exception抛出而已), 我们可以把一个FutureTask提交给线程池的Executor来执行. FutureTask, 除了作为一个单独的类之外, 它的protected 方法在我们自定义Task的时候是非常有用的.

3.2 执行过程

public class FutureTask<V> implements RunnableFuture<V> {
    public void run() {
        // 不了解compareAndSwapObject方法的可以去查找CAS相关文章了解下.
        // 如果state不是NEW的情况, 说明任务已经被执行了, 直接返回.  
        if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            //在任务执行的过程中, 可能会调用cancel(). 这里主要是不想让中断操作逃逸到run()方法之外
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    
    protected void set(V v) { // 更改当前任务的状态并把任务执行的结果写入到outcome当中, 最后由get()取出来用
        // 将当前任务状态置为:COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            // 将当前任务状态置为:NORMAL
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }
    
    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            // 将waiters栈的栈顶置为null
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t); // 这里唤醒的是awaitDone()阻塞的线程
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }

        done(); // 一个钩子方法, 本类中, 它是一个空实现, 在子类中可以重写它. 
        callable = null;        // to reduce footprint
    }
    
    protected void setException(Throwable t) {
        // 将当前任务状态置为:COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = t;
            // 将当前任务状态置为:EXCEPTIONAL
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            finishCompletion();
        }
    }
    
    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;
    }
}

当一个任务正常执行完成, FutureTask的状态转变为: NEW -> COMPLETING -> NORMAL.

当一个任务执行过程中出现异常, FutureTask的状态转变为: NEW -> COMPLETING -> EXCEPTIONAL

当一个任务执行过程中被调用cancel方法取消了, FutureTask的状态转变为: NEW -> INTERRUPTING -> INTERRUPTED(参数为true) 或者 NEW -> CANCELLED(参数为false)

FutureTask生命周期

3.3 获取结果

public class FutureTask<V> implements RunnableFuture<V> {
    
    // 两个get方法中, 主要还是调用awaitDone方法.
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException(); // 带有超时时间的get(), 如果超过指定时间, 就会抛出一个TimeoutException
        return report(s);
    }
    
    // 等待任务完成
    private int awaitDone(boolean timed, long nanos) throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            if (Thread.interrupted()) { 
                // 如果线程被中断了, 移除无效节点并抛出一个中断异常
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state; // 当前任务状态保存到s变量里
            if (s > COMPLETING) { // 如果当前状态大于COMPLETING, 说明任务已经结果了
                if (q != null)
                    q.thread = null;
                return s;
            } else if (s == COMPLETING) { // cannot time out yet
                // 如果当前的任务状态为COMPLETING, 因为该状态的停留的时间非常短, 通过yield()尝试把时间片交给其他线程处理, 然后重试
                Thread.yield();
            } else if (q == null) {
                q = new WaitNode(); // 初始化q节点, 然后重试
            } else if (!queued) { // 将WaitNode放入栈中
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
            } else if (timed) {
                // 如果有超时限制的话, 判断是否超时, 如果没有超时就重试, 如果超时了, 就把q节点从栈中遇除
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q); // 移除无效节点
                    return state; 
                }
                LockSupport.parkNanos(this, nanos); // LockSupport是一个并发工具, 这里表示等待nanos秒后唤醒
            } else {
                LockSupport.park(this); // 开始阻塞线程, 直到任务完成了才会再次唤醒了在finishCompletion()中唤醒
            }
        }
    }
    
    /**
     * 将某个节点置为无效节点, 并清除栈中所有的无效节点(通过前面的分析, 应该可以推断出, 无效的节点, 其实就是指节点内部的thread == null)
     * 那么产生无效节点的情况就有三种了. 
     * (1): 线程被中断了
     * (2): s > COMPLETING即当前的任务状态 > COMPLETING
     * (3): 超时
     */
    private void removeWaiter(WaitNode node) {
        if (node != null) {
            node.thread = null;
            retry:
            for (;;) {          
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    s = q.next;
                    if (q.thread != null) {
                        pred = q;
                    } else if (pred != null) {
                        pred.next = s; // 删除当前节点
                        // 如果前驱节点也是一个无效节点, 则重新遍历, 否则就代表清理完成了
                        if (pred.thread == null) // check for race
                            continue retry;
                    } else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, q, s)) {
                        // 如果当前节点q是无效节点并且没有前驱节点(也就是栈顶节点), 则将栈顶置为当前节点q的后继节点, 再遍历.
                        continue retry;
                    }
                }
                break;
            }
        }
    }
    
    private V report(int s) throws ExecutionException {
        Object x = outcome; // 我们在set()方法的时候把结果写进outcome的
        if (s == NORMAL) // 如果是正常直接返回任务执行的结果
            return (V)x;
        if (s >= CANCELLED) // 如果是被取消了, 或者是被中断了就返回一个CancellationException
            throw new CancellationException();
        throw new ExecutionException((Throwable) x); // 或者返回一个ExecutionException
    } 
}

4. shutdown方法

了解了submit和execute方法后, 我们来了解下线程池的关闭方法

public class ThreadPoolExecutor extends AbstractExecutorService {
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 检查shutdown权限
            checkShutdownAccess();
            // 设置线程池控制状态为SHUTDOWN
            advanceRunState(SHUTDOWN);
            // 中断所有空闲的工作线程
            interruptIdleWorkers();
            // shutdown的钩子方法
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        // 尝试终止
        tryTerminate();
    }
    
    final void tryTerminate() {
        for (;;) {
            int c = ctl.get(); // 获取线程池的控制状态
            // 线程池的运行状态为RUNNING || 线程池的运行状态最小要大于TIDYING || 线程池的运行状态为SHUTDOWN并且workQueue队列不为null
            if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return; // 不能终止, 直接返回
            if (workerCountOf(c) != 0) { // Eligible to terminate
                // 线程池正在运行的worker数量不为0, 仅仅中断一个空闲的worker
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // 比较并设置线程池控制状态为TIDYING
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated(); // 终止线程池的钩子方法
                    } finally {
                        // 设置线程池控制状态为TERMINATED
                        ctl.set(ctlOf(TERMINATED, 0));
                        // 释放在termination条件上等待的所有线程
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }
}

5. 总结

到此, 线程池ThreadPoolExecutor的核心代码已经分析完成. 线程池在多线程开发的环境下的作用是非常大的, 只有深刻理解了线程池的基本原理, 了解线程池细致的实现过程, 才能更好地使用它, 再出现问题之后, 也更容易排查.

posted on 2021-02-22 17:18  annwyn  阅读(109)  评论(0)    收藏  举报

导航