目录
方法advanceRunState,tryTerminate,checkShutdownAccess,3个interruptXXX
字段only_one,方法reject,onShuntdown,isRunningOrShutdown,drainQueue,addWorker
方法addWorkerFailed,processWorkerExit,getTask,runworker
4个构造函数,方法execute,shutdown,shutdownNow
方法3个isXXX,awaitTermination,finalize,5个getXXX/setXXX,ensurePrestart,2个prestartXXX,2个allowXXX
方法getQueue,purge,5个getXXX,toString,before/afterExecute,terminated
简介
package java.util.concurrent;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.*;
/**
* 一个executor服务,使用可能的几个线程池中的一个
* 来执行每个提交的任务,通常使用Executors的工厂方法来配置。
*
* <p>线程池解决两个不同的问题:当执行大量异步任务时,
* 线程池通常提供更好的性能,因为它们减少了每个任务调用的开销;
* 线程池提供了一种绑定和管理在执行任务集合时消耗的资源(包括线程)的方法。
* 每个ThreadPoolExecutor还维护一些基本统计信息,比如已完成任务的数量。
*
* <p>这个类提供了许多可调整的参数和可扩展钩子,以便在广泛的上下文中使用。
* 然而,程序员被敦促使用更方便的executor工厂方法executor。
* Executors.newCachedThreadPool(无绑定的线程池,自动回收线程)。
* Executors.newFixedThreadPool(固定大小的线程池)。
* Executors.newSingleThreadExecutor(单个后台线程),为最常见的使用场景预配置设置。
* 否则,在手动配置和调优该类时,请使用以下指南:
*
* <p>
*
* <p>核心和最大池大小
*
* <p>一个ThreadPoolExecutor会根据corePoolSize(见getCorePoolSize)和
* maximumPoolSize(见getMaximumPoolSize)设置的边界自动调整池大小(见getPoolSize)。
*
* 当一个新的任务在方法execute(Runnable)中提交,并且少于corePoolSize线程正在运行,
* 一个新的线程被创建来处理请求,即使其他工作线程是空闲的。
* 如果运行的线程多于corePoolSize但少于maximumPoolSize,则只有在队列满的情况下才会创建新的线程。
* 通过设置corePoolSize和maximumPoolSize相同,您可以创建一个固定大小的线程池。
* 通过将maximumPoolSize设置为一个本质上无界的值,比如Integer.MAX_VALUE,允许池容纳任意数量的并发任务。
* 最典型的是,核心池和最大池大小仅在构建时设置,但它们也可以使用setCorePoolSize和setMaximumPoolSize动态更改。
*
* <p>按需建设
*
* <p>默认情况下,即使是核心线程最初也只在新任务到达时创建和启动,
* 但这可以使用prestartCoreThread或prestartAllCoreThreads方法动态覆盖。
* 如果使用非空队列构造池,可能需要预启动线程。
*
* <p>创建新线程
*
* <p>使用ThreadFactory创建新线程。如果没有另外指定,使用Executors.defaultThreadFactory,
* 它创建的线程都在同一个ThreadGroup中,并且具有相同的NORM_PRIORITY优先级和非守护状态。
*
* 通过提供不同的ThreadFactory,您可以改变线程的名称、线程组、优先级、守护进程状态等。
* 如果ThreadFactory通过从newThread返回null来创建线程失败,执行器将继续,但可能无法执行任何任务。
*
* 线程应该拥有"modifyThread"运行时权限。
* 如果worker线程或其他使用该池的线程不具有此权限,服务可能会降级:
* 配置更改可能无法及时生效,关闭池可能仍处于可能终止但未完成的状态。
*
* <p>保活时间
*
* <p>如果池当前有超过corePoolSize的线程,如果它们已经空闲超过keepAliveTime(参见getKeepAliveTime(TimeUnit)),多余的线程将被终止。
* 当池没有被积极使用时,这提供了一种减少资源消耗的方法。
* 如果池在以后变得更活跃,将构造新的线程。
* 这个参数也可以使用setKeepAliveTime(long, TimeUnit)方法动态更改。
* 使用Long.MAX_VALUE TimeUnit纳秒有效地禁止空闲线程在关闭之前终止。
* 缺省情况下,keep-alive策略只在有超过corePoolSize线程时适用。
* 但是方法allowCoreThreadTimeOut(boolean)也可以用于将这种超时策略应用到核心线程,只要keepAliveTime值不为零。
*
* <p>队列
*
* <p>任何BlockingQueue都可以用来传输和保持已提交的任务。
* 这个队列的使用与池大小相互作用:
*
* <ul>
*
* <li> 如果运行的线程少于corePoolSize,执行器总是倾向于添加新的线程而不是排队。</li>
*
* <li> 如果corePoolSize或更多的线程正在运行,执行器总是更喜欢排队请求而不是添加一个新的线程。</li>
*
* <li>如果一个请求不能被排队,一个新的线程被创建,除非这个线程超过了maximumPoolSize,在这种情况下,任务将被拒绝。</li>
*
* </ul>
*
* 一般有三种排队策略:
*
* <ol>
*
* <li> 直接的传递。
* 对于工作队列来说,一个不错的默认选择是SynchronousQueue,它可以将任务交给线程,而不用保存它们。
* 在这里,如果没有立即可用的线程来运行一个任务,那么将其放入队列的尝试将失败,因此将构造一个新的线程。
* 该策略避免了在处理可能具有内部依赖性的请求集时的锁定。
* 直接切换通常需要无限制的最大池大小,以避免拒绝新提交的任务。
* 这反过来承认,当命令继续以比处理速度快的速度到达时,线程可能无限增长。</li>
*
* <li>无界队列。
* 使用一个无界队列(例如LinkedBlockingQueue没有预定义的容量)
* 将导致新的任务在所有corePoolSize线程繁忙时在队列中等待。
* 因此,只会创建corePoolSize个线程。(maximumPoolSize的值没有任何影响。)
*
* 当每个任务完全独立于其他任务时,这可能是合适的,这样任务就不会影响其他任务的执行;
* 例如,在web页面服务器中。
* 虽然这种类型的排队在平滑请求的短暂爆发方面很有用,
* 但它承认,当命令持续以比处理速度快的速度到达时,工作队列可能会无限制地增长。</li>
*
* <li>有界的队列。
* 有界队列(例如ArrayBlockingQueue)在使用有限的最大池大小时有助于防止资源耗尽,但可能更难调整和控制。
* 队列大小和最大池大小可能会相互交换:
* 使用大队列和小池可以最小化cpu使用量、操作系统资源和上下文切换开销,但可能会导致人为的低吞吐量。
* 如果任务经常阻塞(例如,如果它们受到I/O限制),系统可能会调度比您允许的更多的线程。
* 使用小队列通常需要更大的池大小,这使cpu更忙,但可能会遇到不可接受的调度开销,这也会降低吞吐量。</li>
*
* </ol>
*
*
*
* <p>拒绝接受任务
*
* <p>在方法execute(Runnable)中提交的新任务将在执行程序关闭,以及执行程序使用了有限的最大线程和工作队列容量,并且达到饱和时被拒绝。
* 在这两种情况下,execute方法都会调用RejectedExecutionHandler的rejectedExecution方法。提供了四个预定义的处理策略:
*
* <ol>
*
* <li> 默认的ThreadPoolExecutor.AbortPolicy,处理程序在拒绝时抛出一个运行时拒绝的RejectedExecutionException。</li>
*
* <li> 调用ThreadPoolExecutor.CallerRunsPolicy的线程自己运行任务。这提供了一个简单的反馈控制机制,可以降低新任务提交的速度。</li>
*
* <li>默认的ThreadPoolExecutor.DiscardPolicy,将不能执行的任务直接删除。 </li>
*
* <li>ThreadPoolExecutor.DiscardOldestPolicy,如果执行程序没有关闭,
* 位于工作队列头部的任务将被丢弃,然后重试执行(可能再次失败,导致重复执行)。</li>
*
* </ol>
*
* 可以定义和使用其他类型的RejectedExecutionHandler类。
* 这样做需要一些小心,特别是当策略被设计为只在特定容量或排队策略下工作时。
*
* <p>钩子方法
*
* <p>这个类提供了受保护的可覆盖的,beforeExecute(Thread, Runnable)和
* afterExecute(Runnable, Throwable)方法,它们在每个任务执行之前和之后被调用。
* 这些可以用来操纵执行环境;
* 例如,重新初始化threadlocals、收集统计信息或添加日志条目。
* 此外,可以覆盖terminated方法,以便在执行程序完全终止后执行许多特殊处理。
*
* <p>如果钩子或回调方法抛出异常,内部工作线程可能会失败并突然终止。
*
* <p>队列的维护
*
* <p>方法getQueue()允许访问工作队列以进行监视和调试。
* 强烈反对将此方法用于任何其他目的。
* 两个提供的方法,remove(Runnable)和purge可以在大量队列任务被取消时帮助存储回收。
*
* <p>终结
*
* <p>一个不再在程序中引用并且没有剩余线程的池将被自动关闭。
* 如果你想确保未引用的线程池被回收,即使用户忘记调用shutdown,
* 那么你必须安排未使用的线程最终死亡,通过设置适当的保持活动时间,
* 使用0核心线程的下限和/或设置allowCoreThreadTimeOut(boolean)。
*
*
*
* <p>扩展的例子。这个类的大多数扩展都覆盖了一个或多个受保护的钩子方法。
* 例如,下面是一个子类,它添加了一个简单的暂停/恢复功能:
*
* <pre> {@code
* class PausableThreadPoolExecutor extends ThreadPoolExecutor {
* private boolean isPaused;
* private ReentrantLock pauseLock = new ReentrantLock();
* private Condition unpaused = pauseLock.newCondition();
*
* public PausableThreadPoolExecutor(...) { super(...); }
*
* protected void beforeExecute(Thread t, Runnable r) {
* super.beforeExecute(t, r);
* pauseLock.lock();
* try {
* while (isPaused) unpaused.await();
* } catch (InterruptedException ie) {
* t.interrupt();
* } finally {
* pauseLock.unlock();
* }
* }
*
* public void pause() {
* pauseLock.lock();
* try {
* isPaused = true;
* } finally {
* pauseLock.unlock();
* }
* }
*
* public void resume() {
* pauseLock.lock();
* try {
* isPaused = false;
* unpaused.signalAll();
* } finally {
* pauseLock.unlock();
* }
* }
* }}</pre>
*
* 理解ThreadPoolExecutor的关键在于理解execute提交task的执行逻辑:
* addWorker(command, true)。在线程数没有达到corePoolSize时,新起一个线程来执行task。核心线程数量内的线程不会被回收。
* workQueue.offer(command)。在线程数达到corePoolSize后,则不起线程,而是先入队task。
* addWorker(command, false)。如果线程数达到corePoolSize且队列已满,则新起一个线程来执行task。但这个线程可能会因为空闲地太久而被回收。
* 阻塞队列的选择也会影响到execute的逻辑。
* 有界队列,使得execute的策略可以正常运行。
* 无界队列,使得maximumPoolSize失去作用。
* 直接提交队列,使得队列失去缓存的作用。
* 线程池关闭后,肯定无法提交新task了。
* 如果执行的是shutdown,每个工作线程完成当前task后还会去执行队列中的剩余task。
* 如果执行的是shutdownNow,队列中剩余task会被清空,每个工作线程完成当前task后,线程池就会结束使命。
* Worker是工作线程的实现,它继承了AQS实现了独占锁部分,目的是为了让工作线程在未开始执行task或正在执行task时,不会被interruptIdleWorkers中断。
* 工作线程执行task期间如果抛出了异常,一定会补充新的工作线程。
*
* @since 1.5
* @author Doug Lea
*/
public class ThreadPoolExecutor extends AbstractExecutorService
各种字段和与ctl相关的方法
/**
* 主池控制状态ctl是一个原子整数,包含两个概念字段
*
* ctl变量把int型的bit分为了两部分:
* 高3位bit作为线程池的状态。
* 低29位bit作为线程数量。
* 而这样做的好处就是,把对两种状态的改变 变成了对同一个变量的CAS操作,毕竟单个CAS操作才是原子的。
*
* workerCount, 表示线程的有效数量
* runState, 指示是否正在运行、关闭等
*
* 为了将它们打包到一个int中,我们将workerCount限制为(2^29)-1(大约5亿)个线程,而不是(2^31)-1(20亿)个线程。
* 如果将来这是一个问题,变量可以更改为AtomicLong,并调整下面的shift/mask常量。
* 但是,在需要之前,使用int可以使这段代码更快更简单。
*
* workerCount是允许开始和不允许停止的工人的数量。
* 该值可能与活动线程的实际数量暂时不同,
* 例如,当ThreadFactory在被请求时创建线程失败,以及退出的线程在终止前仍在执行簿记时。
* 用户可见的池大小报告为工作者集的当前大小。
*
* runState提供了主要的生命周期控制,其值为:
*
* RUNNING: 接受新任务并处理排队的任务
* SHUTDOWN: 不接受新任务,但处理排队的任务
* STOP: 不接受新任务,不处理排队的任务,中断正在进行的任务
* TIDYING: 所有的任务已经终止,workerCount为0,转换到TIDYING的线程将运行terminated()钩子方法
* TERMINATED: terminated()已经完成
*
* 这些数值之间的数字顺序很重要,因为要进行有序比较。
* 运行状态随时间单调增加,但不必达到每个状态。转换:
*
* RUNNING -> SHUTDOWN
* 在调用shutdown()时,可能隐式地在finalize()中调用
*
* (RUNNING or SHUTDOWN) -> STOP
* 调用shutdownNow()
*
* SHUTDOWN -> TIDYING
* 当队列和池都为空时
*
* STOP -> TIDYING
* 当池都为空时
*
* TIDYING -> TERMINATED
* 当terminated()钩子方法完成时
*
* 其实后面函数的逻辑,其复杂点都体现在了对线程池状态非RUNNING的检测了。线程池状态如果是RUNNING,逻辑还是很清楚。
*
* 在awaitTermination()中等待的线程将在状态达到TERMINATED时返回。
*
* 检测从SHUTDOWN过渡到TIDYING不如你想因为简单,队列可能成为空后非空,在SHUTDOWN状态反之亦然,
* 但我们只能终止,如果在看到它是空的,我们看到workerCount为0(有时需要复核,见下文)。
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; // 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 00011111111111111111111111 29个1
// runState 存储在高阶位中
// 不难发现,这几个线程池状态无论后面的29位bit是什么,它们的大小顺序是完全的从小到大的顺序。
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
// 包装和拆装ctl
private static int runStateOf(int c) { return c & ~CAPACITY; } // & 1110000000000000000000000 29个0
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
/*
* 不需要拆装ctl的位字段访问器。
* 这取决于位布局和workerCount绝不为负。
*/
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
/**
* 尝试cas递增ctl的workerCount字段。
*/
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
/**
* 尝试cas递减ctl的workerCount字段。
*/
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
/**
* 减少ctl的workerCount字段。
* 这只在线程突然终止时被调用(参见processWorkerExit)。其他的递减是在getTask中执行的。
*/
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
/**
* 用于保存任务并将任务移交给工作线程的队列。
* 我们不要求workQueue.poll()返回null就一定意味着workQueue.isEmpty(),
* 所以完全依赖isEmpty来查看队列是否为空
* (例如,当决定是否从关闭转换为清理时,我们必须这样做)。
* 这适用于特殊用途的队列,如DelayQueues,允许poll()返回null,即使稍后当时间过期了,返回非null。
*
* Direct handoffs
* 这种队列提供一种生产者直接提交task给消费者的功能,比如SynchronousQueue。
* 生产者调用会ThreadPoolExecutor.execute(command) -> workQueue.offer(command),offer有两种表现:
* 1. 已有消费者在等待,那么返回true,代表直接转交task给消费者
* 2. 没有消费者在等待,那么直接返回false,代表转交失败。这也说明线程池的SynchronousQueue内只可能有request node。
* 由上一条可知,工作线程数量达到核心线程数时,再提交task就会马上创建新线程,前提是满足maximumPoolSize的限制。
* 所以看来,SynchronousQueue是根本起不到缓存task的作用的。
*
* Unbounded queues
* 无界队列,比如LinkedBlockingQueue。此时maximumPoolSizes不会起到作用,
* 因为当线程数量已经达到核心线程数时,再调用workQueue.offer(command)肯定会入队成功返回true。
* 如果消费者处理task太慢,会导致task队列无限增长(无限缓存task),可能导致内存不足。
* LinkedBlockingQueue也可以设置容量,最好进行设置。
* LinkedBlockingQueue内部使用两个锁分别控制入队和出队,效率相对更高。
*
* Bounded queues
* 有界队列,比如ArrayBlockingQueue。此时ThreadPoolExecutor的execute方法的策略能起到作用。
* 入队和出队时竞争的是同一个锁,并发效率比LinkedBlockingQueue低。
*/
private final BlockingQueue<Runnable> workQueue;
/**
* 锁持有对工人集和相关簿记的访问。
* 虽然我们可以使用某种类型的并发集,但通常使用锁更可取。
* 其中一个原因是,这序列化了interruptIdleWorkers,避免了不必要的中断风暴,特别是在关闭期间。
* 否则,退出的线程将并发地中断那些尚未中断的线程。
* 它还简化了一些相关的统计簿记,如largestPoolSize等。
* 我们也会在shutdown和shutdownNow保持主锁,以确保工人设置是稳定的,同时分别检查中断和实际中断的权限。
*/
private final ReentrantLock mainLock = new ReentrantLock();
/**
* 集合,包含池中的所有工作线程。只有当持有主锁时才能访问。
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
* 支持awaitTermination的等待条件
*/
private final Condition termination = mainLock.newCondition();
/**
* 池的最大大小。只有持有主锁才能访问。
*/
private int largestPoolSize;
/**
* 计数器显示已完成的任务。只在工作线程终止时更新。仅在mainLock下访问。
*/
private long completedTaskCount;
/*
* 所有用户控制参数都声明为volatile,这样正在进行的操作就基于最新的值,
* 但不需要锁定,因为没有内部不变量依赖于它们与其他操作同步更改。
*/
/**
* 新线程的工厂。所有线程都是使用这个工厂(通过addWorker方法)创建的。
* 所有的调用者必须为addWorker的失败做好准备,这可能反映了系统或用户的策略,限制了线程的数量。
* 即使它不是一个错误,创建线程失败可能会导致新的任务被拒绝,或者现有的任务仍然被困在队列中。
*
* 我们更进一步,即使遇到诸如OutOfMemoryError这样的错误(可能在创建线程时抛出),也保留了池的不变量。
* 由于需要在线程中分配本地堆栈,这样的错误是相当常见的。启动时,用户将希望执行清理池关闭以进行清理。
* 可能会有足够的内存来完成清理代码,而不会遇到另一个OutOfMemoryError。
*/
private volatile ThreadFactory threadFactory;
/**
* 处理程序在饱和或在执行中关闭时调用。
*
* 两种情况消费者来提交task会被拒绝:
* 工作线程数达到了maxmumPoolSize,且task队列已满。
* 线程池正在关闭,或已经关闭。
*/
private volatile RejectedExecutionHandler handler;
/**
* 等待工作的空闲线程的超时(以纳秒计)。
* 当有超过corePoolSize或如果allowCoreThreadTimeOut为true时,线程使用这个超时。
* 否则,他们将永远等待新的工作。
*/
private volatile long keepAliveTime;
/**
* 如果为false(默认值),核心线程即使在空闲时也保持活动。
* 如果为真,核心线程使用keepAliveTime超时等待工作。
*/
private volatile boolean allowCoreThreadTimeOut;
/**
* corePoolSize是工作者存活的最小数量。
* 除非设置了allowCoreThreadTimeOutis,在这种情况下,最小值为零。
*/
private volatile int corePoolSize;
/**
* 最大池大小。注意,实际的最大值在内部受到容量的限制。
*/
private volatile int maximumPoolSize;
/**
* 默认拒绝执行处理程序
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
/**
* shutdown和shutdownNow的调用者需要许可。
* 我们还要求(参见checkShutdownAccess)调用者拥有真正中断工作线程集中线程的权限(由Thread.interrupt管理,它依赖于ThreadGroup.checkAccess)。
* 这反过来又依赖于SecurityManager .checkAccess)。
* 只有当这些检查通过时,才会尝试关闭。
*
* 所有实际调用Thread.interrupt (看interruptIdleWorkers和interruptWorkers)都忽略安全异常,这意味着尝试的中断静默失败。
* 在关闭的情况下,它们不应该失败,除非SecurityManager有不一致的策略,有时允许访问线程,有时不允许。
* 在这种情况下,没有真正中断线程可能会禁用或延迟完全终止。
* interruptIdleWorkers的其他用途是建议性的,实际中断失败仅仅会延迟对配置更改的响应,因此不会异常处理。
*/
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
内部类Worker
/**
* Worker类主要维护运行任务的线程的中断控制状态,以及其他次要的簿记。
* 这个类机会地扩展了AbstractQueuedSynchronizer以简化获取和释放围绕每个任务执行的锁。
* 这可以防止中断从中断正在运行的任务中唤醒正在等待任务的工作线程。
* 我们实现了一个简单的非重入的互斥锁而不是使用ReentrantLock,
* 因为我们不希望worker任务在调用像setCorePoolSize这样的池控制方法时能够重新获得锁。
* 此外,为了在线程真正开始运行任务之前抑制中断,我们将锁的状态初始化为负值,并在启动时清除它(在runWorker)。
*
* Worker封装了每个工作线程。
*
* 可以看到Worker继承了AQS,目的是为了使用AQS的同步队列。继承了就需要实现AQS的抽象方法。
*
* 仅仅为了使用AQS的独占锁部分。利用独占锁的互斥,可以工作线程在从未开始时(state为-1)和正在执行task期间(state为1)不会被中断。
* 对tryAcquire的实现是不可重入的,原因之后再讲。总之,为了避免因不可重入而无限阻塞,只要避免当前线程持有锁的情况再去acquire(1),就不会出现无限阻塞。
* 相反,tryAcquire总会是安全的。
*
* 我们知道在runWorker中,如果worker线程还没有开始,或者正在执行task,state一定是非0的,这就使得别的线程无法获得worker锁。
* 这样别的线程在调用interruptIdleWorkers时,是无法中断正在执行task的worker线程的。
* 而独占锁被设计为不可重入的原因是为了防止自己中断自己。
* 比如生产者传入的task是这样实现的:
* class MyTask implements Runnable {
* @Override
* public void run() {
* threadPoolExecutor.setCorePoolSize(10);
* }
* }
* 而setCorePoolSize里又有可能调用到interruptIdleWorkers,所以不可重入就防止了自己中断自己。
*/
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** 这个工作器正在运行的线程。如果工厂失败,则为Null。 */
final Thread thread;
/** 要运行的初始任务。可能是null */
Runnable firstTask;
/** 线程任务计数器 */
volatile long completedTasks;
/**
* 使用ThreadFactory提供的第一个任务和线程创建。
*
* Worker的首要目的是保存线程对象和这个工作线程的第一个task。从下面的构造器可以看到。
*
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
// Executors.java
//static class DefaultThreadFactory implements ThreadFactory {
// public Thread newThread(Runnable r) {//这里传的是Worker实例
// Thread t = new Thread(group, r,
// namePrefix + threadNumber.getAndIncrement(),
// 0);
// return t;
// }
//}
this.thread = getThreadFactory().newThread(this);
}
/** 将主运行循环委托给外部runWorker */
public void run() {
runWorker(this);
}
// 锁方法
// 0代表未解锁
// 值1表示锁定状态。
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
方法advanceRunState,tryTerminate,checkShutdownAccess,3个interruptXXX
/*
* 设置控制状态的方法
*/
/**
* 转换运行状态到给定目标,或者在至少给定目标的情况下不进行转换。
*
* @param targetState the desired state, either SHUTDOWN or STOP
* (but not TIDYING or TERMINATED -- use tryTerminate for that)
*/
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
/**
* 如果(SHUTDOWN,池和队列为空)或(STOP,池为空),则转换为TERMINATED状态。
* 如果符合终止条件,但是workerCount不为0,则中断一个空闲的worker以确保shutdown信号的传播。
* 这个方法必须在任何可能导致终止的操作之后调用——减少工人数量或在关闭期间从队列中删除任务。
* 该方法是非私有的,允许从ScheduledThreadPoolExecutor访问。
*
* 此函数检测到可以帮忙时,就把当前状态变成TIDYING,执行完terminated()后,再把状态变成TERMINATED。
*/
final void tryTerminate() {
for (;;) {
int c = ctl.get();
if (isRunning(c) ||//当前还是Running,那么根本不应该tryTerminate
runStateAtLeast(c, TIDYING) ||//已经是TIDYING,那么不需要当前线程去帮忙了
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))//虽然SHUTDOWN,但任务队列非空
return;
//1. 状态为SHUTDOWN,任务队列为空,继续尝试
//2. 状态为STOP
//如果线程数量都不是0,那么肯定不能tryTerminate,直接返回
if (workerCountOf(c) != 0) {
//中断一个空闲线程,中断状态会自己传播
interruptIdleWorkers(ONLY_ONE);
return;
}
//说明线程数量确实为0。现在已经满足可以帮助的条件
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//CAS更新为TIDYING状态
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();//空实现
} finally {
//谁变成了TIDYING,谁就负责变成TERMINATED(这解释了前面遇到TIDYING的情况)
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();//已经获得了锁,现在可以唤醒条件队列的线程了
}
return;
}
} finally {
mainLock.unlock();
}
// ctl.compareAndSet(c, ctlOf(TIDYING, 0))如果失败走这里,肯定是因为别的线程
// 把状态变成了TIDYING状态。下一次循环会直接退出
}
}
/*
* 用于控制对工作线程的中断的方法。
*/
/**
* 如果有安全管理器,确保调用者具有关闭线程的权限(参见shutdownPerm)。
* 如果通过,还要确保调用者被允许中断每个工作线程。
* 即使第一次检查通过了,如果SecurityManager特别对待某些线程,这也可能不成立。
*/
private void checkShutdownAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
/**
* 中断所有线程,即使是活动的。忽略安全异常
* (在这种情况下,一些线程可能保持不中断)。
*/
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
/**
* 中断可能正在等待任务的线程(通过未被锁定表示),以便它们可以检查是否终止或配置更改。
* 忽视SecurityExceptions(在这种情况下,一些线程可能保持不中断)。
*
* @param onlyOne 如果是这样,最多打断一个工人。
* 只有当终止被启用,但仍然有其他worker时,才会从tryTerminate调用这个函数。
* 在这种情况下,在所有线程都在等待的情况下,最多会中断一个等待的工作线程来传播关闭信号。
* 中断任意线程可以确保在shutdown开始后新到达的workers也将最终退出。
*
* 为了保证最终的终止,它总是只中断一个空闲的工人,但是shutdown()中断所有空闲的工人,
* 使多余的工人及时退出,而不是等待一个掉队的任务完成。
*
* 此函数尝试中断空闲的Worker线程。
* Worker线程在执行task的前提是持有自己的Worker锁,
* 相反,空闲的线程是没有持有自己的Worker锁的,所以当前线程执行w.tryLock()是能返回true的。
* 参数onlyOne为true时,只中断一个空闲的Worker线程。
*
* 我们执行这句t.interrupt(),就中断了Worker线程。
* 但Worker线程是怎么做到“只中断一个,就传播这个中断状态”的,我们还得看Worker的实现。
*/
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
//没有被中断过的线程,并且这个线程并没有在运行task(运行task时会持有worker锁)
//注意,w.tryLock()一定得放到右边,不然可能获得锁后不释放锁
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)//只中断一个空闲线程即可
break;
}
} finally {
mainLock.unlock();
}
}
/**
* interruptIdleWorkers的常见形式,以避免必须记住布尔参数的含义。
*/
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
字段only_one,方法reject,onShuntdown,isRunningOrShutdown,drainQueue,addWorker
private static final boolean ONLY_ONE = true;
/*
* 杂项实用程序,其中大多数也导出到ScheduledThreadPoolExecutor
*/
/**
* 为给定的命令调用被拒绝的执行处理程序。包保护,供ScheduledThreadPoolExecutor使用。
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
/**
* 在调用shutdown时执行运行状态转换后执行任何进一步的清理。
* 这里是一个no-op,但是被ScheduledThreadPoolExecutor用来取消延迟的任务。
*/
void onShutdown() {
}
/**
* ScheduledThreadPoolExecutor需要的状态检查,以在关闭期间启用运行的任务。
*
* @param shutdownOK true if should return true if SHUTDOWN
*/
final boolean isRunningOrShutdown(boolean shutdownOK) {
int rs = runStateOf(ctl.get());
return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
}
/**
* 将任务队列排入一个新的列表,通常使用drainto。
* 但是,如果队列是DelayQueue或poll或drainTo
* 可能无法删除某些元素的任何其他类型的队列,则会一个接一个地删除它们。
*/
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = 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;
}
/*
* 用于创建、运行和清理工作器的方法
*/
/**
* 检查是否可以根据当前池的状态和给定边界(core或maximum)添加一个新的worker。
* 如果是这样,将相应地调整worker计数,并且,如果可能的话,将创建并启动一个新的worker,并将firstTask作为它的第一个任务运行。
* 如果池已经停止,这个方法将返回false。如果被请求时线程工厂创建线程失败,它也返回false。
* 如果线程创建失败,或者是由于线程工厂返回null,或者是由于异常(通常是OutOfMemoryError inThread.start()),我们将干净地回滚。
*
* @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 如果为true,则使用corePoolSize作为绑定,否则使用maximumPoolSize。
* (这里使用了一个布尔指示器而不是values,以确保在检查其他poolstate后读取新值)。
* @return true if successful
*/
private boolean addWorker(Runnable firstTask, boolean core) {
// 想要新起线程,就必须将ctl的线程数量部分加1。
// 但这还有个大前提,那就是线程状态必须符合下面两种情况,才需要新起线程。
// 1.状态为RUNNING。
// 2.状态为SHUTDOWN,且task队列非空,这种情况需要新起线程来执行剩余task。
// 当然,firstTask参数必须null,因为此时不允许处理新task了。
// 并且如果firstTask参数为null,那么新起线程将会从task队列中取出一个来执行,这就达到了 新起线程来执行剩余task 的目的。
// ctl的线程数量部分成功加1后,就需要创建新线程,并启动线程。
// 利用线程工厂创建Worker,Worker里包含了新线程。
// 检测线程池状态没有发生变化后(符合上面两种情况),将Worker加入集合,启动新线程。
// 检测线程池状态发生变化后,那新线程不能被启动,则需要把已创建的Worker从集合中移除,并且把ctl的线程数量部分再减1(其实就是addWorkerFailed)。
// 总之,此函数返回true就代表新线程成功启动了;返回false,就是因为当前线程池状态不对而没有启动新线程。
// 另外,在new Worker(firstTask)内部利用了线程工厂来创建的新Thread。
retry://该循环在检测线程池状态的前提下,和线程数量限制的前提下,尝试增加线程数量
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 如果状态已经不是running了
if (rs >= SHUTDOWN &&
// 三者都成立,括号内才返回true,括号外才返回false,函数才不会直接return
// 三者只要有一个不成立,那么addWorker将直接返回false
! (rs == SHUTDOWN && //当前是SHUTDOWN状态
firstTask == null && //传入参数是null(非null说明是新task,但已经SHUTDOWN所以不能再添加)
! workQueue.isEmpty())) //队列非空
//即有三种情况会造成addWorker直接false,不去新起线程了;还有一种特殊情况,addWorker会继续执行。
//1. 如果当前是STOP以及以后的状态(肯定不需要新起线程了,因为task队列为空了)
//2. 如果当前是SHUTDOWN,且firstTask参数不为null(非RUNNING状态线程池都不可以接受新task的)
//3. 如果当前是SHUTDOWN,且firstTask参数为null,但队列空(既然队列空,那么也不需要新起线程)
//1. 如果当前是SHUTDOWN,且firstTask参数为null,且队列非空(特殊情况,需要新起线程把队列剩余task执行完)
return false;
//此时说明,需要新起线程(状态为RUNNING或SHUTDOWN)
for (;;) {
int wc = workerCountOf(c);
//如果线程数量超过最大值
if (wc >= CAPACITY ||
//如果线程数量超过特定值,根据core参数决定是哪个特定值
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))//CAS尝试+1一次
//如果CAS成功,说明这个外循环任务完成,退出大循环
break retry;
//CAS修改失败可能是:线程数量被并发修改了,或者线程池状态都变了
c = ctl.get();
if (runStateOf(c) != rs) //再次检查当前线程池状态,和当初保存的线程池状态
continue retry; //如果改变,那么continue外循环,即重新检查线程池状态(毕竟线程池状态也在这个int里)
// 如果只是 线程数量被并发修改了,那么接下来会继续内循环,再次CAS增加线程数量
}
}
//此时,crl的线程数量已经成功加一,且线程池状态保持不变(相较于函数刚进入时)
boolean workerStarted = false;//新线程是否已经开始运行
boolean workerAdded = false;//新线程是否已经加入set
Worker w = null;
try {
w = new Worker(firstTask);//构造器中利用线程工厂得到新线程对象
final Thread t = w.thread;//获得这个新线程
if (t != null) {//防止工厂没有创建出新线程
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//加锁不是为了ctl,而是为了workers.add(w)
try {
// 需要再次检查状态
int rs = runStateOf(ctl.get());
//如果线程还是运行状态
if (rs < SHUTDOWN ||
//如果线程是SHUTDOWN,且参数firstTask为null
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // 新线程肯定是还没有开始运行的
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 {
//只要线程工厂创建线程成功,那么workerStarted为false只能是因为线程池状态发生变化,且现在一定不是running状态了
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
方法addWorkerFailed,processWorkerExit,getTask,runworker
/**
* 回滚工作线程的创建。
* -从工人中移除工人,如果存在
* -减少工人计数
* -重新检查是否终止,如果这个工人的存在阻碍了终止
*
* 此函数把已创建的Worker从集合中移除(如果存在的话),并且把ctl的线程数量部分再减1。
* 不过前面也说过,调用addWorkerFailed的前提很可能是线程池状态发生了变化,所以这里需要tryTerminate。
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)//如果集合存在,移除它
workers.remove(w);
decrementWorkerCount();//循环CAS,直到成功减一
tryTerminate();//帮忙terminate
} finally {
mainLock.unlock();
}
}
/**
* 为垂死的工人做清理和记账工作。仅从工作线程调用。
* 除非设置了completedAbruptly,否则假定workerCount已经调整为考虑退出。
* 如果它由于用户任务异常退出,或如果少于corepoolsize工作线程正在运行,或队列非空但没有工作线程,
* 这个方法从工作线程集中移除线程,并可能终止线程池或替换工作线程。
*
* 当前线程已经从runWorker中的循环中退出,可能是因为getTask返回null,也可能是执行task时抛出了异常。
* 总之,当前worker线程已经马上要寿终正寝了,所以来调用processWorkerExit。
*
* @param w the worker
* @param completedAbruptly if the worker died due to user exception
*/
//传入Worker已经马上要寿终正寝
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 前面做了一些收尾工作,比如ctl减一,workers移除。当前worker即将要寿终正寝,但可能需要在结束前补充一个worker。
// 如果当前worker是因为抛出异常从而结束自己生命的,那么肯定补充(!completedAbruptly为false)。
// 如果当前worker是因为getTask返回null从而结束自己生命的,那么在当前线程数量不够最小线程数时,才会去补充。
// 这也解释了interruptIdleWorkers(ONLY_ONE)为什么会传播中断状态。
// 因为一个空闲的工作线程被中断后,会去执行processWorkerExit里的tryTerminate,
// 而tryTerminate里又会去调用interruptIdleWorkers(ONLY_ONE)唤醒另一个空闲线程。
if (completedAbruptly) // 如果runWorker中的循环不是正常结束的,则需要此函数来减小线程数
decrementWorkerCount(); // 否则是runWorker里的getTask做了这件事(getTask返回了null)
//此时,ctl的线程数量是不包括传入Worker了
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//传入Worker的完成任务数量 加到 线程池的总和上去
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();//帮助Terminate
int c = ctl.get();
if (runStateLessThan(c, STOP)) {//如果状态为RUNNING或SHUTDOWN,才可能需要补充线程
//但补充前还需要判断一下
if (!completedAbruptly) {//如果传入Worker是正常结束的
//min表示线程池的最小线程数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())//如果为0且队列非空,那么需要再加1
min = 1;
if (workerCountOf(c) >= min)//如果当前线程数量满足要求
return; // 那么不需要补充线程,直接返回
}
// 1. 如果传入Worker是因为抛出异常而结束,那么肯定补充
// 2. 如果传入Worker是正常结束,那么视需要而补充
addWorker(null, false);//补充一个线程
}
}
/**
* 根据当前配置设置,对任务执行阻塞或定时等待,如果由于以下任何原因必须退出,则返回null:
* 1. 有更多的工人(由于调用setMaximumPoolSize)。
* 2. 池已停止。
* 3. 池关闭,队列为空。
* 4. 这个工作线程在等待一个任务时超时了,
* 超时的工作线程在超时等待之前和之后都会被终止(即allowCoreThreadTimeOut || workerCount > corePoolSize),
* 如果队列不是空的,这个工作线程就不是池中的最后一个线程。
*
* 此函数尝试从task队列取得一个task,注意在getTask执行时,当前worker线程是没有持有自己的worker锁的,所以在getTask中支持被中断。
*
* @return task, or null if the worker must exit, in which case
* workerCount is decremented
*/
private Runnable getTask() {
// 在获取队列元素之前,必须要判断线程池状态和其他一些情况。视情况而定,可能会直接返回null,代表获取失败或者说不应该由当前线程来获取。
// 如果线程池状态为SHUTDOWN且队列为空,那么没有task可以让当前线程获得,返回null。
// 如果线程池状态为STOP(隐含队列为空),那么没有task可以让当前线程获得,返回null。
// 如果不是上面的情况,那么只是说明有task可以取。但还得继续判断情况,如果同时满足以下两个情况则则不可以去取task(返回null):
// 1.如果当前线程数量已经超过maximumPoolSize(这是因为动态调小了maximumPoolSize),或者虽然没有超过但上一次的超时poll动作已经超时了
// (做超时操作的前提是allowCoreThreadTimeOut || wc > corePoolSize,既然超时了,当前线程也就不用去取task了)。
// 满足的话,说明当前线程应该是需要放弃取task的,但还得满足下一个情况。
// 2.因为即将放弃取task,所以得防止“队列里有task但是没有工作线程在工作”的情况。在队列非空时,除了当前线程还必须有别的线程,毕竟当前线程马上要放弃了。
// 满足了上面两种情况,则当前线程要放弃取task了,但在结束getTask之前要把ctl的线程数量减一。
// 但CAS修改ctl的线程数量可能失败,失败后再次走上面的流程。
// 完全有可能,失败后再走上面流程就不会放弃了,比如当前线程数量为corePoolSize+1(考虑allowCoreThreadTimeOut为false),
// 有两个工作线程都超时了,第一个线程放弃并修改线程数量成功,
// 第二个线程也想放弃但修改ctl失败下一次循环发现wc > corePoolSize不成立,也就不放弃了,继续去做取task动作。
// 上面这些判断都通过了,说明当前线程确实需要取得一个task。
// 根据timed变量做 限时阻塞的出队动作、或无限阻塞的出队动作。如果成功出队一个task,则返回它。
// 总之,getTask返回非null值代表当前worker线程应该继续工作;
// 返回null值代表当前条件下获取task失败,当前条件是考虑了线程池状态和当前线程状态(是否超过核心线程数,是否限时阻塞已经超时)。
boolean timedOut = false; //保存超时poll操作是否操作,
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 这里条件是一个组合关系:
// 1. rs >= SHUTDOWN 和 workQueue.isEmpty() 说明没有task可以获得了
// 2. rs >= SHUTDOWN 和 rs >= STOP(隐式的说明 task队列为空)
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();//循环CAS,直到线程数量减一
return null;//返回null代表取task失败
}
int wc = workerCountOf(c);
// 这个变量控制,出队操作是否需要为超时版本。
// 1. 如果allowCoreThreadTimeOut为true,那么所有线程都会使用超时版本的出队操作
// 2. 如果wc > corePoolSize,那么超过部分的线程应该使用超时版本的出队操作
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 第一个表达式((wc > maximumPoolSize || (timed && timedOut))
// 如果wc大于了最大线程数(因为动态调小了maximumPoolSize)或超时操作已经超时,
// 这说明当前worker很可能需要抛弃。
// 第二个表达式(wc > 1 || workQueue.isEmpty())
// 如果线程数至少为2(除了当前worker线程外还有其他线程),
// 或者线程数为1(只有当前worker线程)但队列为空:
// 这说明不用担心,队列剩余task没有线程去取,即确定了当前worker需要抛弃
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))//如果CAS尝试减一成功
return null;//直接返回null
continue;//如果CAS失败,可能有多个线程同时修改了ctl的线程数。
//而这个分支是否还会进入需要下一个循环再判断
}
try {
Runnable r = timed ?//根据变量来判断,使用超时poll,还是take
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) ://限时阻塞
workQueue.take();//无限阻塞
if (r != null)//成功获得了task
return r;
//只有限时阻塞才可能返回null,且肯定是超时操作超时了
timedOut = true;
} catch (InterruptedException retry) {
//无论上面是哪种操作,在阻塞期间被中断的话,当前worker线程会抛出中断异常
timedOut = false;//不算超时,所以这里设为false
//继续下一次循环,下一次可能会返回null
}
}
}
/**
* 主工作程序运行循环。
* 重复地从队列中获取任务并执行它们,同时要处理以下几个问题:
*
* 1. 我们可以从一个初始任务开始,在这种情况下,我们不需要得到第一个任务。
* 否则,只要pool正在运行,我们就从getTask获取任务。如果它返回null,那么worker由于池状态或配置参数的改变而退出。
* 其他的退出来源于异常在外部代码中抛出,在这种情况下completedAbruptly持有,这通常导致processWorkerExit替换该线程。
*
* 2. 在运行任何任务之前,需要获取锁来防止其他线程池在任务执行时中断,
* 然后我们确保除非线程池停止,否则这个线程没有设置中断集。
*
* 3. 每个任务运行之前都有一个beforeExecute调用,这可能会抛出异常,
* 在这种情况下,我们导致线程死亡(以completedAbruptly true中断循环),而不处理该任务。
*
* 4. 假设beforeExecute正常完成,我们运行任务,收集其抛出的任何异常发送到afterExecute。
* 我们分别处理RuntimeException、Error(这两个都是保证我们捕获的)和任意Throwables。
* 因为我们不能在Runnable.run中重新抛出Throwables,所以我们在退出时将它们包装在错误中(到线程的UncaughtExceptionHandler)。
* 任何抛出的异常也会保守地导致线程死亡。
*
* 5. task.run完成后,我们调用afterExecute,这也可能抛出异常,也会导致线程死亡。
* 根据JLS第14.20节,即使task.run抛出异常,这个异常也会生效。
*
* 异常机制的最终效果是,afterExecute和线程的UncaughtExceptionHandler
* 提供了我们所能提供的关于用户代码遇到的任何问题的准确信息。
*
* runWorker是线程池工作线程的全部运行逻辑,一定是工作线程来执行runWorker的。
*
* @param w the worker
*/
final void runWorker(Worker w) {
// 进入循环前,将state设置为0,使得Worker锁可以被抢。
// 循环是工作线程的主要逻辑,每次循环通过条件里的getTask()获得task来执行。当然,getTask()必然是可以阻塞等待直到从队列取得元素的。
// 执行task前,必须先消耗中断状态(如果线程已被中断),因为中断状态不清理会导致getTask()里无法阻塞。
// 并且只有在线程池状态为STOP时(task队列已空)且线程已被中断,才恢复线程的中断状态
//(这看起来可以用来保证,在当前循环执行task后下一次循环getTask()会抛出中断异常,但实际上getTask()发现STOP状态会直接返回null;
// 当然还有一种可能,就是task.run()会检测中断状态抛出中断异常)。
// 执行task前,先执行beforeExecute。如果抛出异常,会导致task.run()不执行。
// 执行task时(task.run()),可能抛出异常。
// 无论执行task时是否抛出异常,都会执行afterExecute。
// 每次循环结束前,无论前面有没有抛出异常,都会清空一些变量,并释放Worker锁,因为这次拿到的task已经执行完毕。
// 从循环结束有两个原因:
// 1. task.run()返回null了,循环正常结束(completedAbruptly为false)。
// 2. 在执行task时抛出了异常,也会结束循环(completedAbruptly为true)。无论哪种情况,当前Worker线程都会马上寿终正寝了。
// 简单的说,runWorker做的就是每次循环中从队列中取出一个task来执行,如果队列为空,那么阻塞等待直到队列非空取到task。这就是每个工作线程的工作内容。
Thread wt = Thread.currentThread();//获得当前线程对象
Runnable task = w.firstTask;//获得第一个task(这里可能为null)
w.firstTask = null;//释放引用
w.unlock(); // 此时state为0,Worker锁此时可以被抢。且此时工作线程可以被中断了
boolean completedAbruptly = true;//是否发生异常
try {
//1. 如果第一个task不为null,开始执行循环
//2. 如果第一个task为null,但从task队列里获得的task不为null,也开始循环
//3. 如果task队列获得到的也是null,那么结束循环
while (task != null || (task = getTask()) != null) {
w.lock();//执行task前,先获得锁
// 第一个表达式 (runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
// 无论线程池状态是什么都会消耗掉当前线程的中断状态(如果当前线程确实被中断了),
// 并且只有线程池状态是STOP的情况下,且当前线程被中断了,才会返回true。
// 第二个表达式 !wt.isInterrupted()
// 因为第一个表达式永远会消耗掉中断状态,所以第二个表达式肯定为true
// 总之,重点在第一个表达式。
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
// 1. 如果线程池状态为STOP,且当前线程被中断,马上恢复中断状态
// 2. 如果线程池状态为其他,且当前线程被中断,仅仅消耗掉这个中断状态,不进入分支
wt.interrupt();//恢复中断状态
try {
//空实现的方法,如果抛出异常,completedAbruptly将为true
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();//执行task
} catch (RuntimeException x) {
thrown = x; throw x;//这里抛出异常,completedAbruptly也将为true
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
//空实现方法
afterExecute(task, thrown);//task.run()抛出异常的话,至少afterExecute可以执行
}
} finally {//无论上面在beforeExecute或task.run()中抛出异常与否,最终都会执行这里
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;//上面循环是正常结束而没有抛出异常,这个变量才为false
} finally {
//无论循环正常结束(getTask返回null,completedAbruptly为false),
//还是循环中抛出了异常(completedAbruptly为true),都会执行这句。
//代表当前Worker马上要寿终正寝了
processWorkerExit(w, completedAbruptly);
}
}
4个构造函数,方法execute,shutdown,shutdownNow
// 公共构造函数和方法
/**
* 使用给定的初始参数、默认线程工厂和拒绝执行处理程序创建新的ThreadPoolExecutor。
* 使用Executors的工厂方法可能比使用这个通用构造函数更方便。
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default rejected execution handler.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
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();
// corePoolSize和maximumPoolSize作为线程数量的限制。corePoolSize最小允许为0,maximumPoolSize最小允许为1。且必须 maximumPoolSize >= corePoolSize。
// 在corePoolSize范围内的工作线程可能得以一直不被回收,但工作线程的数量不会超过maximumPoolSize的。
// keepAliveTime作为空闲线程等待超时时间。一般情况下,线程数量超过corePoolSize时,空闲线程超时后会被回收;
// 但如果允许CoreThreadTimeOut,那么线程数量即使没超过corePoolSize(这些都是核心线程),空闲线程超时后也会被回收。
// workQueue作为task队列,它是一个阻塞队列。我们把线程池的工作线程称为消费者,执行线程池.execute()的线程称为生产者。
// 当消费者想取出元素而队列为空时,消费者可能会阻塞;当生产者想放入元素而队列已满时,生产者可能会阻塞。
// threadFactor作为线程工厂,传入Runnable返回一个新Thread对象。有默认的Executors.defaultThreadFactory。
// handler作为拒绝策略。当线程池状态为RUNNING时,如果工作线程数量已经达到maxmumPoolSize,且task队列已满,生产者会被拒绝;
// 当线程池状态非RUNNING时,生产者肯定被拒绝。
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
/**
* 在将来的某个时候执行给定的任务。
* 该任务可以在新线程中执行,也可以在现有的线程池中执行。
*
* 如果无法提交任务执行(因为该executor已经关闭或其容量已达到),
* 则该任务将由当前RejectedExecutionHandler处理。
*
* 生产者传递一个task给线程池,线程池负责异步地执行这个task,
* 如果task既不能被马上执行,也不能入队,那么将执行拒绝策略。
*
* @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) {
if (command == null)
throw new NullPointerException();
// 其实上面这个过程体现了corePoolSize、maximumPoolSize、task队列大小 之间的关系。我们把关键步骤拎出来,并忽略那些检测线程池非RUNNING状态的逻辑的话,那么只有这三步:
// addWorker(command, true)。第二个实参代表如果线程数没有超过corePoolSize,那么新增一个线程直接执行task,自然,这个task不会被入队。
// workQueue.offer(command)。将task入队,如果入队成功,说明没有超过队列大小。
// addWorker(command, false)。第二个实参代表如果线程数没有超过maximumPoolSize,那么新增一个线程直接执行task,自然,这个task不会被入队。
// 这三步总是按照顺序执行的,根据corePoolSize、maximumPoolSize、task队列大小,这里体现了execute的执行策略:
// 如果线程数量小于corePoolSize,那么不入队,尝试起一个新线程来执行task。
// 如果线程数量大于等于了corePoolSize,那么只要队列未满,就将task入队。
// 如果线程数量大于等于了corePoolSize,且队列已满(上一步入队失败)。那么以maximumPoolSize作为限制,再起一个新线程。——addWorker(command, false)成功。
// 如果线程数量大于等于了maximumPoolSize,且队列已满。那么将执行拒绝策略。——addWorker(command, false)失败。
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { //如果正在运行的线程数量 < corePoolSize
//那么直接尝试把task交给一个新线程处理,不用先入队task了
if (addWorker(command, true)) //如果起新线程成功了,直接返回
return;
//执行到这里,说明情况发生了变化。
c = ctl.get();
}
// 如果线程池还在运行中,而且task入队成功
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();//入队成功后还需要再次检查
// 如果线程池不是运行状态了,而且task出队成功
if (! isRunning(recheck) && remove(command))
//执行拒绝策略
reject(command);
//1. 线程池是运行状态
//2. 线程池不是运行状态,但task出队失败
else if (workerCountOf(recheck) == 0)
//因为corePoolSize允许为0,且有可能刚入队后,池里唯一的线程就死掉了
addWorker(null, false);
//1. 如果线程池不在运行中
//2. 如果线程池在运行中,但入队失败了
else if (!addWorker(command, false)) //尝试新起一个线程来处理task
reject(command);
}
}
/**
* 启动一个有序的关闭,在这个关闭中,先前提交的任务将被执行,但是不会接受新的任务。
* 如果已经关闭,则调用没有额外的效果。
*
* <p>此方法不等待以前提交的任务完成执行。使用一个awaitTermination来实现。
*
* @throws SecurityException {@inheritDoc}
*/
public void shutdown() {
// 线程池状态变成SHUTDOWN后,就无法再提交新task给线程池了。
// interruptIdleWorkers可以中断那些阻塞在workQueue.超时poll或workQueue.take上的线程,
// 它们被中断后,可能会继续取出队列中的task来执行,更可能结束掉自己的生命。
// 有可能此时已经满足了Terminate的条件,所以必须尝试一下tryTerminate。
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();//检查权限
advanceRunState(SHUTDOWN);//改变线程池状态
interruptIdleWorkers();//中断所有空闲线程
onShutdown(); // 钩子方法,空实现
} finally {
mainLock.unlock();
}
tryTerminate();//尝试Terminate
}
/**
* 尝试停止所有正在执行的任务,停止处理正在等待的任务,并返回等待执行的任务列表。
* 从此方法返回时,这些任务将从任务队列中被清空(删除)。
*
* <p>此方法不等待正在执行的任务结束。使用awaitTermination来完成这个操作。
*
* <p>除了尽最大努力尝试停止处理正在执行的任务之外,没有任何保证。
* 这个实现通过Thread.interrupt取消任务,因此任何没有响应中断的任务都可能永远不会终止。
*
* @throws SecurityException {@inheritDoc}
*/
public List<Runnable> shutdownNow() {
// 线程池状态变成STOP后,同样无法再提交新task给线程池了。
// interruptWorkers中断不仅中断空闲线程,正在工作的线程也会中断,注意这无视了工作线程已经持有的worker锁。
// 但如果工作线程的执行task不关心中断的话,那么也没有意义。
// tasks = drainQueue()清空队列。
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
方法3个isXXX,awaitTermination,finalize,5个getXXX/setXXX,ensurePrestart,2个prestartXXX,2个allowXXX
public boolean isShutdown() {
return ! isRunning(ctl.get());
}
/**
* 如果执行器正在shutdown或shutdownNow,终止但尚未完全终止,则返回true。
* 这个方法对于调试可能很有用。
* 如果在关闭后的足够时间内返回true,则可能表明提交的任务忽略或抑制了中断,导致这个执行器不能正确终止。
*
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
public boolean isTerminated() {
return runStateAtLeast(ctl.get(), TERMINATED);
}
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
// 此函数可以让当前线程一直阻塞直到线程池所有任务都结束、或者超时。
// 总之,就是利用了AQS的条件队列,让等待Termination的线程都阻塞在条件队列上。
// 当然,在tryTerminate中,会执行termination.signalAll()来唤醒条件队列上的所有线程。
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)//如果发现剩余时间少于0,说明超时
return false;
nanos = termination.awaitNanos(nanos);//限时阻塞,阻塞在这个termination条件队列上
}
} finally {
mainLock.unlock();
}
}
/**
* 当此执行程序不再被引用且没有线程时,调用shutdown。
*/
protected void finalize() {
shutdown();
}
/**
* Sets the thread factory used to create new threads.
*
* @param threadFactory the new thread factory
* @throws NullPointerException if threadFactory is null
* @see #getThreadFactory
*/
public void setThreadFactory(ThreadFactory threadFactory) {
if (threadFactory == null)
throw new NullPointerException();
this.threadFactory = threadFactory;
}
/**
* Returns the thread factory used to create new threads.
*
* @return the current thread factory
* @see #setThreadFactory(ThreadFactory)
*/
public ThreadFactory getThreadFactory() {
return threadFactory;
}
/**
* Sets a new handler for unexecutable tasks.
*
* @param handler the new handler
* @throws NullPointerException if handler is null
* @see #getRejectedExecutionHandler
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
if (handler == null)
throw new NullPointerException();
this.handler = handler;
}
/**
* Returns the current handler for unexecutable tasks.
*
* @return the current handler
* @see #setRejectedExecutionHandler(RejectedExecutionHandler)
*/
public RejectedExecutionHandler getRejectedExecutionHandler() {
return handler;
}
/**
* 设置线程的核心数量。
* 这将覆盖构造函数中设置的任何值。
* 如果新值小于当前值,那么多余的现有线程将在它们下次变为空闲时被终止。
* 如果更大,如果需要,将启动新线程来执行任何队列任务。
*
* @param corePoolSize the new core size
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @see #getCorePoolSize
*/
public void setCorePoolSize(int corePoolSize) {
// 此函数设置新的corePoolSize,相较之前如果发生了变化,则需要多退少补。
// corePoolSize变小,则需要停止掉一些空闲的核心线程。
// corePoolSize变大,则需要补充一些新的核心线程,但如果发现队列为空就不需要再增加了。
if (corePoolSize < 0)
throw new IllegalArgumentException();
// 如果参数比成员大,delta将会是正数。可能需要增加核心线程
// 如果参数比成员小,delta将会是负数。可能需要停止一些核心线程
int delta = corePoolSize - this.corePoolSize;
this.corePoolSize = corePoolSize;
if (workerCountOf(ctl.get()) > corePoolSize)//如果现有线程数已经大于最新的corePoolSize
interruptIdleWorkers();//通过中断空闲线程来终止它们
else if (delta > 0) {//需要增加核心线程
//不用非得加delta个,有可能只需要加 队列大小那么多就够了
int k = Math.min(delta, workQueue.size());
while (k-- > 0 && addWorker(null, true)) {//循环添加
if (workQueue.isEmpty())//当发现队列为空,其实就不需要加核心线程
break;
}
}
}
/**
* Returns the core number of threads.
*
* @return the core number of threads
* @see #setCorePoolSize
*/
public int getCorePoolSize() {
return corePoolSize;
}
/**
* 启动一个核心线程,导致它无所事事地等待工作。
* 这覆盖了只有在执行新任务时才启动核心线程的默认策略。
* 如果所有的核心线程都已经启动,这个方法将返回false。
*
* 初始化线程池后,如果没有生产者来调用execute之类的方法的话,是肯定不会启动任何线程的。
* 所以,如果构造线程池时给的task队列非空,那么直到第一次调用execute之前,都不会有任何一个工作线程。
*
* @return {@code true} if a thread was started
*/
public boolean prestartCoreThread() {
//如果线程数小于corePoolSize,才会尝试增加一个worker
return workerCountOf(ctl.get()) < corePoolSize &&
addWorker(null, true);
}
/**
* 与prestartCoreThread相同,除了安排至少一个线程启动,即使corePoolSize是0。
*/
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}
/**
* 启动所有核心线程,导致它们无所事事地等待工作。
* 这覆盖了只有在执行新任务时才启动核心线程的默认策略。
*
* @return the number of threads started
*/
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))//addWorker第二个参数为true,所以只会增加corePoolSize个线程
++n;
return n;
}
/**
* Returns true if this pool allows core threads to time out and
* terminate if no tasks arrive within the keepAlive time, being
* replaced if needed when new tasks arrive. When true, the same
* keep-alive policy applying to non-core threads applies also to
* core threads. When false (the default), core threads are never
* terminated due to lack of incoming tasks.
*
* @return {@code true} if core threads are allowed to time out,
* else {@code false}
*
* @since 1.6
*/
public boolean allowsCoreThreadTimeOut() {
return allowCoreThreadTimeOut;
}
/**
* 设置策略,控制如果在保持活动时间内没有任务到达,核心线程是否会超时和终止,
* 当新的任务到达时,是否需要被替换。
*
* 当为false时,内核线程不会因为缺少传入的任务而终止。
* 当为true时,应用于non-core线程的keep-alive策略也适用于核心线程。
*
* 为了避免连续的线程替换,当设置为true时,保持活动时间必须大于0。
* 通常应该在积极使用池之前调用此方法。
*
* @param value {@code true} if should time out, else {@code false}
* @throws IllegalArgumentException if value is {@code true}
* and the current keep-alive time is not greater than zero
*
* @since 1.6
*/
public void allowCoreThreadTimeOut(boolean value) {
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;
if (value)
interruptIdleWorkers();
}
}
/**
* 设置允许的最大线程数。这将覆盖构造函数中设置的任何值。
* 如果新值小于当前值,那么多余的现有线程将在下次空闲时被终止。
*
* @param maximumPoolSize the new maximum
* @throws IllegalArgumentException if the new maximum is
* less than or equal to zero, or
* less than the {@linkplain #getCorePoolSize core pool size}
* @see #getMaximumPoolSize
*/
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)//必要的检查
throw new IllegalArgumentException();
this.maximumPoolSize = maximumPoolSize;
if (workerCountOf(ctl.get()) > maximumPoolSize)
interruptIdleWorkers();//被中断的线程,会发现自己多余的存在,然后结束掉自己
}
/**
* Returns the maximum allowed number of threads.
*
* @return the maximum allowed number of threads
* @see #setMaximumPoolSize
*/
public int getMaximumPoolSize() {
return maximumPoolSize;
}
/**
* 设置线程在被终止之前保持空闲的时间限制。
* 如果池中当前的线程数超过核心线程数,在等待这个时间后不处理任务,多余的线程将被终止。
* 这将覆盖构造函数中设置的任何值。
*
* @param time the time to wait. A time value of zero will cause
* excess threads to terminate immediately after executing tasks.
* @param unit the time unit of the {@code time} argument
* @throws IllegalArgumentException if {@code time} less than zero or
* if {@code time} is zero and {@code allowsCoreThreadTimeOut}
* @see #getKeepAliveTime(TimeUnit)
*/
public void setKeepAliveTime(long time, TimeUnit unit) {
// KeepAliveTime=0和allowsCoreThreadTimeOut=true不可兼得。
// 如果KeepAliveTime=0(allowsCoreThreadTimeOut肯定为false),会造成核心数量以外的线程在发现队列为空时,就马上结束自己。
if (time < 0)
throw new IllegalArgumentException();
if (time == 0 && allowsCoreThreadTimeOut())//不可兼得
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
long keepAliveTime = unit.toNanos(time);
long delta = keepAliveTime - this.keepAliveTime;
this.keepAliveTime = keepAliveTime;
if (delta < 0)//如果新的keepAliveTime更小
interruptIdleWorkers();
}
/**
* Returns the thread keep-alive time, which is the amount of time
* that threads in excess of the core pool size may remain
* idle before being terminated.
*
* @param unit the desired time unit of the result
* @return the time limit
* @see #setKeepAliveTime(long, TimeUnit)
*/
public long getKeepAliveTime(TimeUnit unit) {
return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
}
方法getQueue,purge,5个getXXX,toString,before/afterExecute,terminated
/* 用户级队列公用方法 */
/**
* 返回此执行程序使用的任务队列。对任务队列的访问主要用于调试和监视。
* 这个队列可能正在被积极使用。检索任务队列并不会阻止已排队的任务执行。
*
* @return the task queue
*/
public BlockingQueue<Runnable> getQueue() {
return workQueue;
}
/**
* 如果该任务存在,则从执行程序的内部队列中删除它,从而导致它在尚未启动时无法运行。
*
* <p>作为取消方案的一部分,这个方法可能是有用的。
* 它可能无法删除在放入内部队列之前已转换为其他形式的任务。
* 例如,使用submit输入的任务可能会转换为维护Future状态的形式。
* 然而,在这种情况下,方法purge可以用来删除那些已取消的Future。
*
* @param task the task to remove
* @return {@code true} if the task was removed
*/
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
/**
* 尝试从工作队列中删除所有已取消的Future任务。
* 这个方法可以作为存储回收操作,对功能没有其他影响。
* 被取消的任务永远不会执行,但可能会在工作队列中累积,直到工作线程可以主动删除它们。
* 调用此方法将尝试现在删除它们。
* 然而,在其他线程的干扰下,这个方法可能无法删除任务。
*/
public void purge() {
final BlockingQueue<Runnable> q = workQueue;
try {
Iterator<Runnable> it = q.iterator();
while (it.hasNext()) {
Runnable r = it.next();
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
it.remove();
}
} catch (ConcurrentModificationException fallThrough) {
// Take slow path if we encounter interference during traversal.
// Make copy for traversal and call remove for cancelled entries.
// The slow path is more likely to be O(N*N).
for (Object r : q.toArray())
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
q.remove(r);
}
tryTerminate(); // In case SHUTDOWN and now empty
}
/* Statistics */
/**
* Returns the current number of threads in the pool.
*
* @return the number of threads
*/
public int getPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Remove rare and surprising possibility of
// isTerminated() && getPoolSize() > 0
return runStateAtLeast(ctl.get(), TIDYING) ? 0
: workers.size();
} finally {
mainLock.unlock();
}
}
/**
* Returns the approximate number of threads that are actively
* executing tasks.
*
* @return the number of threads
*/
public int getActiveCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int n = 0;
for (Worker w : workers)
if (w.isLocked())
++n;
return n;
} finally {
mainLock.unlock();
}
}
/**
* Returns the largest number of threads that have ever
* simultaneously been in the pool.
*
* @return the number of threads
*/
public int getLargestPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
return largestPoolSize;
} finally {
mainLock.unlock();
}
}
/**
* Returns the approximate total number of tasks that have ever been
* scheduled for execution. Because the states of tasks and
* threads may change dynamically during computation, the returned
* value is only an approximation.
*
* @return the number of tasks
*/
public long getTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers) {
n += w.completedTasks;
if (w.isLocked())
++n;
}
return n + workQueue.size();
} finally {
mainLock.unlock();
}
}
/**
* Returns the approximate total number of tasks that have
* completed execution. Because the states of tasks and threads
* may change dynamically during computation, the returned value
* is only an approximation, but one that does not ever decrease
* across successive calls.
*
* @return the number of tasks
*/
public long getCompletedTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers)
n += w.completedTasks;
return n;
} finally {
mainLock.unlock();
}
}
/**
* Returns a string identifying this pool, as well as its state,
* including indications of run state and estimated worker and
* task counts.
*
* @return a string identifying this pool, as well as its state
*/
public String toString() {
long ncompleted;
int nworkers, nactive;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
ncompleted = completedTaskCount;
nactive = 0;
nworkers = workers.size();
for (Worker w : workers) {
ncompleted += w.completedTasks;
if (w.isLocked())
++nactive;
}
} finally {
mainLock.unlock();
}
int c = ctl.get();
String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
(runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down"));
return super.toString() +
"[" + rs +
", pool size = " + nworkers +
", active threads = " + nactive +
", queued tasks = " + workQueue.size() +
", completed tasks = " + ncompleted +
"]";
}
/* Extension hooks */
/**
* 方法在给定线程中执行给定的可运行程序之前调用。
* 该方法由将执行任务r的线程t调用,并可用于重新初始化ThreadLocals或执行日志记录。
*
* <p>这个实现什么也不做,但可以在子类中自定义。
* 注意:要正确嵌套多个重写,子类通常应该调用super.beforeExecute在这个方法的末尾。
*
* @param t the thread that will run task {@code r}
* @param r the task that will be executed
*/
protected void beforeExecute(Thread t, Runnable r) { }
/**
* 方法在完成给定可运行程序的执行时调用。该方法由执行任务的线程调用。
* 如果非null,则抛出对象是导致执行突然终止的,未捕获的RuntimeException或者Error。
*
* <p>这个实现什么也不做,但可以在子类中自定义。
* 注意:要正确嵌套多个重写,子类通常应该在这个方法的开头执行调用super.afterExecute。
*
* <p>注意:当动作被显式地或通过方法(如submit)封装在任务(如FutureTask)中时,
* 这些任务对象会捕获和维护计算异常,因此它们不会导致突然终止,内部异常也不会传递给这个方法。
* 如果你想在这个方法中捕捉这两种失败,你可以进一步探测这种情况,
* 就像在这个示例子类中,如果一个任务被中止,它将打印直接原因或底层异常:
*
* <pre> {@code
* class ExtendedExecutor extends ThreadPoolExecutor {
* // ...
* protected void afterExecute(Runnable r, Throwable t) {
* super.afterExecute(r, t);
* if (t == null && r instanceof Future<?>) {
* try {
* Object result = ((Future<?>) r).get();
* } catch (CancellationException ce) {
* t = ce;
* } catch (ExecutionException ee) {
* t = ee.getCause();
* } catch (InterruptedException ie) {
* Thread.currentThread().interrupt(); // ignore/reset
* }
* }
* if (t != null)
* System.out.println(t);
* }
* }}</pre>
*
* @param r the runnable that has completed
* @param t the exception that caused termination, or null if
* execution completed normally
*/
protected void afterExecute(Runnable r, Throwable t) { }
/**
* 方法在执行程序终止时调用。默认实现不做任何事情。
* 注意:要正确嵌套多个重写,子类通常应该调用super.terminated在此方法中。
*/
protected void terminated() { }
4个XXXPolicy
/* Predefined RejectedExecutionHandlers */
/**
* 一个被拒绝任务的处理程序,它在execute方法的调用线程中直接运行被拒绝的任务,
* 除非执行程序已经关闭,在这种情况下任务将被丢弃。
*
* 只要线程池还处于RUNNING状态,就让调用者同步执行这个task。否则,直接不给任何提示,放弃执行这个task。
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
/**
* 一个被拒绝任务的处理程序,它抛出一个RejectedExecutionException。
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* 永远RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
/**
* 一个处理被拒绝任务的程序,它静默地丢弃被拒绝的任务。
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* 什么都不做,这有丢弃任务r的效果。
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
/**
* 一个被拒绝任务的处理程序,它丢弃最旧的未处理的请求,
* 然后重试execute,除非executor关闭,在这种情况下任务被丢弃。
*
* 如果线程池已经处于非RUNNING状态,不给任何提示,放弃执行这个task。
* 如果是RUNNING状态,那么出队那个入队最久的task即队头task,然后把参数Runnable r再次提交给线程池,但也不一定再次提交就不会被拒绝。
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* 获取并忽略执行器将执行的下一个任务(如果一个任务是立即可用的),
* 然后重试任务r,除非执行器关闭,在这种情况下任务r被丢弃。
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}