构造方法
 
首先声明 JDK 版本为 jdk1.8.0_121
 
ThreadPoolExecutor 有四种构造方法,前面的三个依赖于最后的那个构造方法
 
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
}

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), handler);
}

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

 

构造方法参数含义如下
 
1)corePoolSize
核心线程数,当线程池中的线程数少于 corePoolSize ,且有新任务时,总是会新开一个线程
 
2)maximumPoolSize
最大的线程数,当使用的是无边界的阻塞队列时,该值会无效。当线程池中的线程数(包括核心和非核心线程) > maximumPoolSize 时,会抛出异常
 
3)keepAliveTime
线程的闲置超时时间,超过这个时间还未获取到任务的线程会被删除
 
4)unit
超时时间的单位
 
5)workQueue
存放任务的阻塞队列,当有线程空闲时,会去获取里面的任务并执行
 
6)threadFactory
线程池中的线程由 threadFactory 来创建
 
7)handler
错误处理,当执行失败时会调用里面的方法进行处理

 

 

Execute
 
方法接收一个 runnable 对象,然后用线程去执行这个对象
 
先看下方法的注释
 
/**
 * Executes the given task sometime in the future.  The task
 * may execute in a new thread or in an existing pooled thread.
 *
 * If the task cannot be submitted for execution, either because this
 * executor has been shutdown or because its capacity has been reached,
 * the task is handled by the current {@code RejectedExecutionHandler}.
 *
 * @param command the task to execute
 * @throws RejectedExecutionException at discretion of
 *         {@code RejectedExecutionHandler}, if the task
 *         cannot be accepted for execution
 * @throws NullPointerException if {@code command} is null
 */
public void execute(Runnable command) {

 

上方注释的大致意思如下:

执行给定的任务在未来的某个时间点内。这个任务可能被新线程执行,也可能被线程池中已经存在的线程执行

如果任务无法被提交,可能是线程池已经是 shutdown 状态或者超出了线程池的容量,这时这个任务会交由 RejectedExecutionHandler 处理

 

接下来看下代码

 

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.
     */
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

 

方法内部依然有一段注释,大致意思是:

1. 如果线程池中的线程数小于 corePoolSize ,会开启一个新的线程,command 参数被会传入到新线程中作为这个线程的第一个任务。addWorker 方法中会原子性的检查 runState 和 workerCount 来防止不应该再添加 worker 。addWorker 方法如果失败将会返回 false

2. 如果任务被成功的加入到队列中,依然会做第二次检查来判断是否需要重新创建一个新线程(因为线程池中原先的线程是有可能挂掉)或者线程池变成了 shutdown 状态

3. 如果任务无法被添加到队列中,我们将会尝试去创建新的线程。如果此时依然失败,可能是线程池处于 shutdown 状态或者线程池是饱和的,此时将会拒绝这个任务

 

根据注释可以知道方法的整个逻辑大致分三种情况
 

1)当前线程数小于核心线程数的情况

2)大于核心线程数且队列没有满,线程池没有中断的情况

3)队列已经排满的情况

 
下面详细说下每一种情况,分别对应源码中的三个 if
 

当前线程数小于核心线程数的情况

 

ctl 是 ThreadPoolExecutor 的一个属性,主要用于计算当前有效的线程数量和连接池的状态。当前线程数实际上就是 worker 的数量。如果任务数小于 corePoolSize,就会执行 addWorker 方法
 

addWorker 方法

 
进入到 addWorker 中,看下方法的注释
 
/**
 * Checks if a new worker can be added with respect to current
 * pool state and the given bound (either core or maximum). If so,
 * the worker count is adjusted accordingly, and, if possible, a
 * new worker is created and started, running firstTask as its
 * first task. This method returns false if the pool is stopped or
 * eligible to shut down. It also returns false if the thread
 * factory fails to create a thread when asked.  If the thread
 * creation fails, either due to the thread factory returning
 * null, or due to an exception (typically OutOfMemoryError in
 * Thread.start()), we roll back cleanly.
 *
 * @param firstTask the task the new thread should run first (or
 * null if none). Workers are created with an initial first task
 * (in method execute()) to bypass queuing when there are fewer
 * than corePoolSize threads (in which case we always start one),
 * or when the queue is full (in which case we must bypass queue).
 * Initially idle threads are usually created via
 * prestartCoreThread or to replace other dying workers.
 *
 * @param core if true use corePoolSize as bound, else
 * maximumPoolSize. (A boolean indicator is used here rather than a
 * value to ensure reads of fresh values after checking other pool
 * state).
 * @return true if successful
 */
 private boolean addWorker(Runnable firstTask, boolean core) {

 

老规矩,看下注释的内容:

1. 检查一个新的 worker 对象能否被添加在当前的线程池状态和给定的约束下。如果是的话,worker 的数量也会做相应的调整,而且如果可能的话,这个新的 worker 被创建后就会被启动执行,传入的 firstTask 属性会作为这个 worker 的第一个任务。方法会返回 false 如果线程池的状态是 stopped 或者 shutdown ,又或者是 threadfactory 创建线程失败、返回 null、抛出异常,此时将会做回滚操作

2. firstTask:新线程需要执行的第一个任务。当线程数小于 corePoolSize 或者队列为空时,这个任务会跳过排队,创建对应的 worker 并被执行作为这个 worker 的第一个任务

3. core:如果是 true,将 corePoolSize 作为边界,否则将 maximumPoolSize 作为边界,当前线程数小于核心线程数的情况中,传入的是 true

 

通过上面的注释,我们大致可以知道整个方法会有以下几个步骤:

1)有效性检查

2)根据 firstTask 创建 worker 对象,视情况判断是否要立即执行 firstTask

3)失败时的回滚

 

1) 有效性检查

 

在有效性判断阶段,通过自旋去判断当前的有效线程数和线程池的状态,如果线程池关闭或者超过了线程池的容量就会返回 false,对应的代码如下,相对比较简单,就不细说了
 
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            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
        }
    }

 

2)创建 worker 对象

 

首先创建一个 Worker 对象,将 firstTask 传进去,然后去判断 worker 中的线程是否已经启动了,如果是则会抛出异常,否则会将 worker 放到 workers 中。最后设置 workerAdded 为 true,启动线程(注意,这里的 start() 并不是去执行 firstTask 里面的 run() 方法),同时设置 workerStarted 为 true

 

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 {
                // 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.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)
            addWorkerFailed(w);
    }
    return workerStarted;
}

 

Worker 类

 

Worker 类是线程池中非常重要的一个类,有必要说一下它,首先是注释

 

/**
 * Class Worker mainly maintains interrupt control state for
 * threads running tasks, along with other minor bookkeeping.
 * This class opportunistically extends AbstractQueuedSynchronizer
 * to simplify acquiring and releasing a lock surrounding each
 * task execution.  This protects against interrupts that are
 * intended to wake up a worker thread waiting for a task from
 * instead interrupting a task being run.  We implement a simple
 * non-reentrant mutual exclusion lock rather than use
 * ReentrantLock because we do not want worker tasks to be able to
 * reacquire the lock when they invoke pool control methods like
 * setCorePoolSize.  Additionally, to suppress interrupts until
 * the thread actually starts running tasks, we initialize lock
 * state to a negative value, and clear it upon start (in
 * runWorker).
 */
private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable

 

注释大致意思如下:

1)Worker 类主要维护线程运行任务和任务的相关状态,以及其他次要的内容。

2)此类继承了AbstractQueuedSynchronizer,以简化获取和释放围绕每个任务执行的锁。同时,Worker 并不会去中断正在运行的任务。我们(设计者)实现了一个简易的不可重入的互斥锁而不是使用 ReentrantLock ,因为我们不希望 worker 当中的任务能够获取到锁在任务调用线程池的一些方法时,如 setCorePoolSize 方法。

此外,在线程真正开始运行任务前,我们将锁定任务的状态初始值为负值,并在启动时将其清除

 

从上面的注释中我们可以得出一个结论:Worker 类维护了任务的状态,会在适当的时候去执行任务

 

明白了这点之后,让我们进到构造方法中,方法首先是将状态设置为了 -1,也就是 Worker 类注释中的将锁定任务的状态初始值为负值,然后将 firstTask 赋值给 Worker 中的 firstTask 变量,最后通过 ThreadFactory 来创建一个新的线程,赋值给 thread 变量

 

/**
 * Creates with given first task and thread from ThreadFactory.
 * @param firstTask the first task (null if none)
 */
Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}
 

接着来看下 threadFactory 是如何创建新线程的,默认的 DefaultThreadFactory 中的 newThread 方法如下,注意,这里传入的 Runnable r 并不是我们先前看到的 firstTask,而是 worker,worker 也实现了 Runnable ,然后根据这个 worker 创建了线程,设置了线程组、线程名,设置线程为非后台线程,设置等级为默认的普通等级
 
public Thread newThread(Runnable r) {
    Thread t = new Thread(group, r,
                          namePrefix + threadNumber.getAndIncrement(),
                          0);
    if (t.isDaemon())
        t.setDaemon(false);
    if (t.getPriority() != Thread.NORM_PRIORITY)
        t.setPriority(Thread.NORM_PRIORITY);
    return t;
}

 

runWork 方法

 

回到创建 Worker 对象的那段代码中,往下走有一句 t.start(),这里的 t 就是 threadFactory 创建的 thread ,里面的 Runnable 为 Worker 类,里面调用了是 runWorker 方法

 

public void run() {
    runWorker(this);
}

 

在看 runWorker 代码之前先来看下方法注释
 
/**
 * Main worker run loop.  Repeatedly gets tasks from queue and
 * executes them, while coping with a number of issues:
 *
 * 1. We may start out with an initial task, in which case we
 * don't need to get the first one. Otherwise, as long as pool is
 * running, we get tasks from getTask. If it returns null then the
 * worker exits due to changed pool state or configuration
 * parameters.  Other exits result from exception throws in
 * external code, in which case completedAbruptly holds, which
 * usually leads processWorkerExit to replace this thread.
 *
 * 2. Before running any task, the lock is acquired to prevent
 * other pool interrupts while the task is executing, and then we
 * ensure that unless pool is stopping, this thread does not have
 * its interrupt set.
 *
 * 3. Each task run is preceded by a call to beforeExecute, which
 * might throw an exception, in which case we cause thread to die
 * (breaking loop with completedAbruptly true) without processing
 * the task.
 *
 * 4. Assuming beforeExecute completes normally, we run the task,
 * gathering any of its thrown exceptions to send to afterExecute.
 * We separately handle RuntimeException, Error (both of which the
 * specs guarantee that we trap) and arbitrary Throwables.
 * Because we cannot rethrow Throwables within Runnable.run, we
 * wrap them within Errors on the way out (to the thread's
 * UncaughtExceptionHandler).  Any thrown exception also
 * conservatively causes thread to die.
 *
 * 5. After task.run completes, we call afterExecute, which may
 * also throw an exception, which will also cause thread to
 * die. According to JLS Sec 14.20, this exception is the one that
 * will be in effect even if task.run throws.
 *
 * The net effect of the exception mechanics is that afterExecute
 * and the thread's UncaughtExceptionHandler have as accurate
 * information as we can provide about any problems encountered by
 * user code.
 *
 * @param w the worker
 */
final void runWorker(Worker w) {

 

意思大致如下:

反复的从队列中获取 tasks 然后执行,处理的逻辑如下:

1. 在 firstTask 未被执行时,会先去执行 firstTask ,否则,只要线程池还在正常工作,就会通过 getTask 方法来获取新的 task ,并执行。如果由于修改了线程池状态或配置参数或抛出异常导致 getTask 方法返回 null,worker 就会退出

2. 在执行任意 task 之前获取锁的目的是防止线程池中别的线程打断了这个 task,然后除非线程池正在停止中,否则执行 task 的线程不会被中断

3. task 在执行 run 之前会先执行 beforeExecute 方法,beforeExecute 有可能会抛出异常,这种情况下将不会去处理 task

4. 假设 beforeExecute 正常执行,将会执行 task 的 run 方法,抛出的异常将会由 afterExecute 方法处理。RuntimeException、Error 、Throwable 将会被分别处理,由于无法在 Runnable 接口的 run 方法中手动抛出异常,我们会将异常包装成 Error。抛出的任意异常都会导致线程死亡

5. afterExecute 会在 task.run() 结束后执行,这个方法依然可能抛出异常,抛出异常同样会导致线程死亡。依据 JLS Sec 14.20,即使 task.run() 抛出异常,也不会使 afterExecute 抛出的异常失效。afterExecute 方法中处理的异常信息就是任务中抛出的异常信息

 
看完注释后,让我们回到代码中,看下代码是怎么写的
 
整体的逻辑是有一个 while 循环,作用就是让 worker 中的线程去执行第一个任务或不断从任务队列里获取任务并执行。当线程中断或者抛出异常时当前线程会被中断,循环也会退出。获取到任务之后,会先执行 beforeExecute,然后执行 task.run 方法,最终执行 afterExecute ,目前 beforeExecute 和 afterExecute 都是空方法
 
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
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                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 {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

protected void beforeExecute(Thread t, Runnable r) { }

protected void afterExecute(Runnable r, Throwable t) { }

 

看到这里,解决了我之前的一个疑惑,那就是 Thread.start() 方法无法被重复调用,那么线程池是如何做到线程的重复利用的
 
原因是 ThreadPoolExecutor 类中有一个 List<Work> workers 列表,每一个 Work 都有一个 Thread (由 ThreadFactory 创建)和 Runnable firstTask,这个 firstTask 会作为 Thread 的第一个任务,而 Thread.start() 只会调用一次,start() 会先去执行 Work 的 run 方法(这里并不会开启另一个线程,始终是在 Thread 中),然后 Work 的 run 方法会去调用 firstTask 的 run 方法。整个执行过程中,Thread 会从队列中不停的获取 task 然后执行,实现问题中的线程重复利用。 Thread (核心线程)并不会停止,直到线程池停止或者 task 抛出异常
 
整个调用链如下图
 

 ThreadPoolExecutor 源码分析_抛出异常
 
 
回到 runWorker 方法中,整个逻辑非常清晰,大致如注释所说,接下来看下 getTask() 方法,按照惯例先看注释
 
/**
 * Performs blocking or timed wait for a task, depending on
 * current configuration settings, or returns null if this worker
 * must exit because of any of:
 * 1. There are more than maximumPoolSize workers (due to
 *    a call to setMaximumPoolSize).
 * 2. The pool is stopped.
 * 3. The pool is shutdown and the queue is empty.
 * 4. This worker timed out waiting for a task, and timed-out
 *    workers are subject to termination (that is,
 *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
 *    both before and after the timed wait, and if the queue is
 *    non-empty, this worker is not the last thread in the pool.
 *
 * @return task, or null if the worker must exit, in which case
 *         workerCount is decremented
 */
private Runnable getTask() {

 

大意如下:

根据当前的配置来获取阻塞或等待中的任务,如果 worker 退出将会返回 null,退出的情况有以下几种:

1. 有超过 maximumPoolSize 的 workers 存在(由于调用 setMaximumPoolSize 修改了 maximumPoolSize 的值)

2. 线程池状态是 stopped

3. 线程池状态是 shutdown 同时阻塞队列是空的

4. worker 获取 task 超时,超时的 worker 将会被解雇(通过 allowCoreThreadTimeOut || wc > corePoolSize 来判断)

 
接下来看下代码,首先是一个自旋,直到获取到 task 或者返回 null。方法会按照注释上的逻辑去做判断,顺利的情况下会从队列中拿到一个 task
 
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.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);

        // Are workers subject to culling?
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

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

 

总结

 

到这里,当前线程数小于核心线程数的情况就算是分析完了,总结一下:

1)worker 是线程池中非常重要的一个对象,里面的 thread 变量就是执行任务的线程

2)worker 的数量相当线程池中当前的线程数量

3)当前线程数小于核心线程数的情况下,会创建新的 worker 对象,worker 中的 thread 会将传入的 command 作为第一个任务并执行

4)getTask 方法是获取队列中的 task ,但不适用于当前线程数小于核心线程数的情况

 

2.  大于核心线程数且队列没有满,线程池没有中断的情况

 

该情况对应的代码如下
 
首先判断线程池是否正在运行,也就是状态值是否小于 c < SHUTDOWN 的情况,然后将 command 提交给阻塞队列,等待被 worker 获取
 
方法做了二次检查,如果线程池不再运行,会移除传入的 command 任务,同时执行 reject 方法,默认的 handler 是 AbortPolicy,就是简单的抛出异常;如果 worker 列表为空,则会创建新的 worker ,并让其从队列中获取刚刚的 command 任务并执行
 
if (isRunning(c) && workQueue.offer(command)) {
    int recheck = ctl.get();
    if (! isRunning(recheck) && remove(command))
        reject(command);
    else if (workerCountOf(recheck) == 0)
        addWorker(null, false);
}
    
private static boolean isRunning(int c) {
    return c < SHUTDOWN;
}

final void reject(Runnable command) {
    handler.rejectedExecution(command, this);
}

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    throw new RejectedExecutionException("Task " + r.toString() +
                                         " rejected from " +
                                         e.toString());
}

 

3.  队列已经排满的情况

 

方法逻辑很简单,队列排满的情况下会直接创建新的 worker 去执行 command ,如果还是失败,则会调用 reject 方法抛出异常,具体方法取决于使用的 RejectedExecutionHandler,已默认的 AbortPolicy 为例,是直接拒绝,抛出异常
 

else if (!addWorker(command, false))
    reject(command);

final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}

 

这里有必要说下 addWorker 返回 false 的情况有哪些

 

从下方代码中可以得出以下两种情况下会返回 false
 

1)线程池已经停止的情况

2)当前的 worker 数量大于等于 CAPACITY 或者大于等于 maximumPoolSize (队列已经排满的情况)的情况

 
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
    ! (rs == SHUTDOWN &&
       firstTask == null &&
       ! workQueue.isEmpty()))
    return false;

int wc = workerCountOf(c);
if (wc >= CAPACITY ||
    wc >= (core ? corePoolSize : maximumPoolSize))
    return false;
    
finally {
    if (! workerStarted)
        addWorkerFailed(w);
}
return workerStarted;  

 

4.  excute 方法总结

 

1)worker 是线程池中非常重要的一个对象,thread 会接收一个 worker(worker 也是一个 runnable),thread.start 相当于让 thread 去执行 worker 的 run 方法

2)worker 的数量相当线程池中当前的线程数量

3)当前线程数小于核心线程数的情况下,会创建新的 worker 对象,worker 中的 thread 会将传入的 command 作为第一个任务并执行

4)当前线程数大于等于核心线程数,会将 command 任务提交到队列中,供核心线程后续调用

5)当提交任务到队列中失败时(往往意味了队列满了),会新建 worker 去执行 command 任务

 

Submit

 

submit 和 execute 方法最大的区别就是 execute 只能接收 Runnable,而 submit 可以接收 Runnable 和 Callable

submit 方法是在 ThreadPoolExecutor 的父类 AbstractExecutorService 里面的,通过源码可以发现最终还是会去调用 execute 方法
 

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

/**
 * @throws RejectedExecutionException {@inheritDoc}
 * @throws NullPointerException       {@inheritDoc}
 */
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;
}

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

 

一般情况下,如果不需要返回值,个人推荐使用 execute 会更好。因为 submit 会将 task 转换为 FutureTask 对象,最终调用 task.run() 的时候,会进入到如下代码中
 
public void run() {
    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 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);
    }
}

 

可以看得最终用的是 c.call() 方法,而如果抛出了异常,会被 catch 住且不会立即抛出,而是会在稍后的 FutureTask.get() 方法中抛出,如果你不去调用,那么异常就会被吞掉,不利于定位问题

 

核心线程和非核心线程

 

查看源码时可以发现,Work 类中并没有哪个属性去标明线程是核心线程还是非核心线程,那么要如何去区分呢?如何做到核心线程一直存活,非核心线程执行完超时退出呢?
 
要回答这两个问题,还是得回到代码中
 
首先是  runWorker 方法,这里截取我们关注的部分,可以发现如果退出了循环体,最终就会执行 processWorkerExit 方法
 
try {
    while (task != null || (task = getTask()) != null) {
        .....
    }
    completedAbruptly = false;
} finally {
    processWorkerExit(w, completedAbruptly);
}

 

processWorkerExit 方法顾名思义就是执行 worker 的退出操作,可以看到 workers.remove(w) 会将当前 worker 移出列表,这样就会被垃圾回收器回收,完成线程的销毁
 
值得注意的是,如果线程池中的线程在执行的时候抛出了异常,那么也会进到该方法中,而且方法后面还会再次调用 addWorker 方法,重新创建一个线程,保证核心线程数的稳定
 
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;
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }

    tryTerminate();

    int c = ctl.get();
    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);
    }
}

 

明白如何销毁线程之后,再来看下 getTask 方法,同样只截取我们关注的部分

 

timed 变量用于判断 workers 是否需要被删除,allowCoreThreadTimeOut 变量用于判断核心线程是否需要去做超时判断,还有一个条件是当前的 worker 数是否大于核心线程数 corePoolSize。如果 timed == true,执行 workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);如果 timed == false,执行 workQueue.take()

 

// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

try {
    Runnable r = timed ?
        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
        workQueue.take();
    if (r != null)
        return r;
    timedOut = true;
} catch (InterruptedException retry) {
    timedOut = false;
}

public E pollFirst(long timeout, TimeUnit unit)
    throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    try {
        E x;
        while ( (x = unlinkFirst()) == null) {
            if (nanos <= 0)
                return null;
            nanos = notEmpty.awaitNanos(nanos);
        }
        return x;
    } finally {
        lock.unlock();
    }
}

public E takeFirst() throws InterruptedException {
    try {
        E x;
        while ( (x = unlinkFirst()) == null)
            notEmpty.await();
        return x;
    } finally {
        lock.unlock();
    }
}

 

总结

 

1)本质上不存在核心线程和非核心线程,两者都放在 workers 对象中。唯一区别就是一个会一直存活并不断获取任务,另一个会在执行完任务后超时退出,但如果 allowCoreThreadTimeOut == true,那么两者都会超时退出
 
2)非核心线程在执行完自己的 firstTask 之后不会立即被销毁,他同样可以像核心线程那样从队列中获取任务并执行,直到队列为空,然后超时退出