一、简介
线程池在并发编程中是个重要的角色, 使用线程池相比于new Thread为每次请求创建一个线程,有效的避免了线程的频繁创建和销毁的开销,java线程是个重量级对象,和操作系统线程对应。首先,频繁的线程切换会使操作系统频繁的进行上下文切换,增加了系统的负载, 其次,线程的创建和销毁是需要耗费系统资源的,明显浪费了系统资源。 线程池技术很好的解决了这个问题,它预先创建一定数量的线程(线程池的数量也需根据特定的机器进行设置,对机器进行大量的测试,得到合理的线程数,后面会出一篇如何得到线程数), 用户不能直接控制线程的创建和销毁, 重复使用固定或者较为固定数目的线程来执行完成任务。这样做的好处: 消除了频繁创建和销毁线程的系统资源开销,面对过量任务的提交能够平缓劣化。ThreadPoolExecutor线程池中有任务队列(未被处理的任务)和线程队列(处理任务的线程队列)。线程池有以下几种状态:①RUNNING: 接受新任务和处理队列任务。 ②SHUTDOWN: 不接受新任务,但处理队列任务。③STOP: 不接受新任务,不处理队列任务(将任务队列中所有未处理的任务全部取走),中断正在进行的任务。④TIDYING: 所有任务都结束,线程池里的线程队列为零,线程池转换到此状态,并且执行terminated()方法,terminated()方法是个空方法,模板方法,子类可以重写实现,比如做一些线程池停止中的清除操作。⑤TERMINATED: terminated()方法执行完成,会由TIDYING转换为TERMINATED状态 。线程池以下几种状态转换:①RUNNING -> SHUTDOWN 调用线程池的shutdown()方法 。②RUNNING or SHUTDOWN -> STOP 调用线程池的shutdownNow()方法 。③SHUTDOWN -> TIDYING 当任务队列和线程池队列都为空 。 ④STOP -> TIDYING 当线程池队列为空,在线程池到STOP状态时会将未处理的任务队列中任务全部取走 。⑤TIDYING -> TERMINATED 当执行terminated()方法完成,terminated是个空方法可以由子类进行重写,做一些清除或者整理的操作 。 先看下线程池对任务的处理流程,下图借鉴网上

线程池是使用生产者消费者的模式,而不是采用每提交一个任务都从线程队列中获取空闲的线程执行任务,线程池中的线程队列的线程执行完第一个给其线程执行的任务,会死循环的从存放未被执行的任务队列中获取任务,如果线程池队列中的非核心线程如果没有从等待队列中获取到任务,或者获取到任务执行任务出现异常,线程都会从线程队列中移除,核心线程如果获取不到任务队列中的任务,等待,直到获取到,或者被中断(中断会重试),判断当前线程队列中的线程数是否小于核心线程数,如果是重新创建一个新的线程,下面会详细介绍到。ExecutorService执行每个提交任务使用一个或者几个线程的线程池,我们通常使用{@link Executors}工厂方法配置。线程池处理两个不同的问题:他们通常提供改进的性能在执行大量的异步任务,由于减少了每个任务的调用开销,还提供了在消耗执行任务集合,提供了边界和管理资源,包括线程。{@code ThreadPoolExecutor}还维护一些基本的统计数据,例如完成任务的数量。为了在一个广泛的背景下是有用的,ThreadPoolExecutor提供了许多可调参数和可扩展性钩子。然而程序员都要求使用更方便的{@link Executors}一系列工厂方法{@link Executors#newCachedThreadPool}(无边界线程池,自动线程回收), {@link Executors#newFixedThreadPool}(固定大小的线程池)和{@link Executors#newSingleThreadExecutor}(单个后台线程)。预先构造设置为最常见的使用场景,接下来看下ThreadPoolExecutor几个核心参数的介绍。①corePoolSize和maximumPoolSize核心和最大线程池大小,{@code ThreadPoolExecutor}会自动调节线程池的大小,可以通过{@link #getPoolSize}查看线程池目前的线程数量,corePoolSize可以通过{@link #getCorePoolSize}进行获取当前线程池设置核心线程的数量,maximumPoolSize可以通过{@link #getMaximumPoolSize}进行获取当前线程池设置的最大线程的数量。当新的任务被提交到线程池,会执行{@link #execute(Runnable)}方法,不到核心运行线程池大小,创建一个新线程来处理请求,即使其他工作线程空闲。如果有超过核心池大小,并且队列已经满,但低于最大池大小线程运行时,将会创建一个新线程。如果corePoolSize和maximumPoolSize设置成相同值,即创建了一个固定大小的线程池。如果设置maximumPoolSize基本上为无限值,如{@code Integer.MAX_VALUE},允许适应任意数量的并发任务。最典型,核心和最大池大小在构造函数进行设置,但也可以使用{@link #setCorePoolSize} 和 {@link #setMaximumPoolSize}动态设置。默认情况下,核心线程最初创建和启动只有当新的任务到来,但这个可以覆盖,动态使用方法{@link #prestartCoreThread}(预先启动一个核心线程)或者 {@link #prestartAllCoreThreads}(预先启动所有的核心线程)②创建线程的ThreadFactory参数,新创建的线程使用{@link ThreadFactory}如果没有设置,默认使用{@link Executors#defaultThreadFactory},此工厂创建线程都在同一个线程组{@link ThreadGroup}和相同的优先级和是否是守护线程。通过自定义一个不同的线程工厂,可以改变线程的名字,线程组、优先级、守护状态。如果{@code ThreadFactory}方法{@code newThread}无法创建一个线程,返回null。线程池会继续,但是可能无法执行任何任务。③keep-alive times如果线程池拥有超过核心线程池大小,多余的线程将被终止,如果他们一直闲置超过维持时间,可以通过{@link #getKeepAliveTime(TimeUnit)}。这提供了一种手段,减少资源消耗,当线程池没有被积极使用。如果线程池后变得更加活跃,新线程将被构造。这个参数也可以动态地改变使用{@link #set Keep Alive Time(long, TimeUnit)}方法。如果值被设置成{@code Long.MAX_VALUE}{@link TimeUnit#NANOSECOND}有效的禁用空闲线程在终止之前关闭。默认情况下,这个参数只适用当有超过核心线程池的大小。但是可以通过{@link #allowCoreThreadTimeOut(boolean)}方法使用这个超时策略应用于核心线程,只要维持这个时间不能是零。④queue队列,可用于传输和保存提交任务。如果少于核心池大小线程正在运行,执行器在任务提交时,总是添加一个新线程,而不是将任务放到队列中。如果线程池有超过核心线程大小的线程正在运行,线程池总是将任务放到队列中,而不是添加一个新线程。如果请求任务不能放到队列中,创建一个新线程,除非这将超过最大池大小,在这种情况下,任务将被拒绝。有三个一般的排队策略,{@link SynchronousQueue}直接传递,将任务直接交给线程而不是持有他们。这里,尝试将任务放到队列如果没有线程立即可以运行将会失败,新的线程将会被构造。直接传递通常需要无限最大池大小来避免拒绝提交的新任务。因为请求继续到达时平均增长速度可能比他们可以被处理快。{@link LinkedBlockingQueue}无边界队列,没有预先设置容量,将会导致新任务在队列中等待当所有的核心线程都在忙。因此从来没有超过核心线程池的大小的线程将被创建。maximumPoolSize参数将不起作用。这可能是适当的,每个任务是完全独立于其他,所以不能影响其他任务的执行。{@link ArrayBlockingQueue}有边界队列,使用有限的maxumumPoolSizes最大池大小有助于预防资源枯竭,但可以调整和控制将会更加困难。队列大小和最大池相互影响,使用大队列和小池减少CPU的使用、操作系统资源和上下文切换开销,但可能导致人为的低吞吐量。使用小队列通常要求更大的池大小,使CPU繁忙但可能遇到不可接受的调度开销,也会降低吞吐量。⑤新任务提交后执行{@link #execute(Runnable)}方法当线程池已经关闭,或者线程池使用有限的范围的最大工作线程和工作队列容量,这些都达到饱和时,在这两种情况下,{@code execute}方法将会调用RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)}。四个预定义的拒绝策略将被提供,1.默认的拒绝策略{@link ThreadPoolExecutor.AbortPolicy},将会直接抛出一个运行时异常{@link RejectedExecutionException}2.{@link ThreadPoolExecutor.CallerRunsPolicy}调用{@code execute}方法线程执行这个任务。这提供了一个简单的反馈控制机制,将减缓新的任务的提交速度。3.{@link ThreadPoolExecutor.DiscardPolicy}新提交的任务将会被直接丢弃4.{@link ThreadPoolExecutor.DiscardOldestPolicy}如果线程池没有关闭,工作队列的最旧的那个任务将会被丢弃,然后执行重试(可以再次失败,造成重复),也可以自定义拒绝策略。⑥提供了几个钩子方法 {@code protected} {@link #beforeExecute(Thread, Runnable)} 和 {@link #afterExecute(Runnable, Throwable)}方法,他们在任务被调用前和任务执行后被调用。这两个方法可以用来操纵执行环境,例如初始化ThreadLocals收集统计信息或者添加日志,方法{@link #terminated}能够被覆盖,执行任何需要做特殊处理,一旦执行者完全终止。还有个onShutdown方法,这个目前在ScheduledThreadPoolExecutor中使用。
二、类关系

Executor
//该接口提供了一种解耦任务的提交与每个任务将如何运行的机制,包括线程使用的细节,调度等
//只提供线程池执行任务的抽象方法
public interface Executor {
//执行给定的任务在将来的一段时间。命令可以执行在一个新线程,线程池,或调用线程,下面会详细进行介绍该方法的实现
void execute(Runnable command);
}ExecutorService
//提供线程池的几种关闭方法,以及判断线程池是否关闭或者结束方法、几种提交任务到线程池的方法,以及线程池执行所有提交上来的任务或者其中一个任务的方法
//以下所有的抽象方法都会在中重写方法中进行详细介绍
public interface ExecutorService extends Executor {
//优雅的关闭线程池,线程池状态会从RUNNING -> SHUTDOWN,不接受新任务,但处理任务队列中的所有未处理任务
void shutdown();
//马上关闭线程池,线程池状态会从RUNNING or SHUTDOWN -> STOP,不接受新任务,不处理队列任务(将任务队列中所有未处理的任务全部取走),中断正在进行的任务
List<Runnable> shutdownNow();
//判断线程池是否关闭
boolean isShutdown();
//判断线程池是否停止
boolean isTerminated();
//等待一段时间,线程池是否停止,如果等待线程池停止的线程被中断,会抛出中断异常
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
//提交Callable类型的任务到线程池中,返回Future对象,Future可以用来获取任务的执行结果,以及阻塞要获取任务结果的线程,不清楚的可以看下我的另一篇FutureTask源码分析
//@throws RejectedExecutionException 如果线程池任务队列满,并且线程队列也已经达到最大线程数,提交上来的任务无法被线程池处理,直接抛出RejectedExecutionException异常
//@throws NullPointerException 如果提交上来的任务为空,会抛出空指针异常
<T> Future<T> submit(Callable<T> task);
//提交Runnable类型的任务到线程中,并且任务执行结果result对象,result对象需要在任务中使用到,Runnable类型的任务会被适配成Callable类型的任务,返回Future对象,Future可以用来获取任务的执行结果,以及阻塞要获取任务结果的线程,不清楚的可以看下我的另一篇FutureTask源码分析
//@throws RejectedExecutionException 如果线程池任务队列满,并且线程队列也已经达到最大线程数,提交上来的任务无法被线程池处理,直接抛出RejectedExecutionException异常
//@throws NullPointerException 如果提交上来的任务为空,会抛出空指针异常
<T> Future<T> submit(Runnable task, T result);
//提交Runnable类型的任务到线程中,没法获取到任务的执行结果,返回Future对象,Future可以用来获取任务的执行结果,以及阻塞要获取任务结果的线程,不清楚的可以看下我的另一篇FutureTask源码分析
//@throws RejectedExecutionException 如果线程池任务队列满,并且线程队列也已经达到最大线程数,提交上来的任务无法被线程池处理,直接抛出RejectedExecutionException异常
//@throws NullPointerException 如果提交上来的任务为空,会抛出空指针异常
Future<?> submit(Runnable task);
//线程池执行提交上来的所有Callable类型的任务,返回所有正确执行完成的任务Future对象,在子类AbstractExecutorService会进行详细的介绍
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
//线程池在超时时间执行提交上来的所有Callable类型的任务,返回所有任务Future对象(包括一些没有被执行任务的Future对象,执行完成的任务Future对象,正在被执行还未执行完成的Future对象,以及还未提交到线程池的Future对象,因为在线程池超时后,可能存在没有被执行的任务,或者还未执行完成的任务),在子类AbstractExecutorService会进行详细的介绍
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
//线程池执行提交上来的任务集合的中的一个个任务,一个一个任务执行,直到有个任务完成,获取第一个完成任务的返回结果
//@return 第一个被线程池执行完成任务的结果
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
//@throws IllegalArgumentException 提交上来的任务集合大小为0,抛出IllegalArgumentException异常
//@throws ExecutionException 如果提交上来的任务集合中,没有一个任务被正确执行完成,会直接抛出ExecutionException异常
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
//线程池在超时时间内执行提交上来的任务集合的中的一个个任务,一个一个任务执行,直到有个任务完成,获取第一个完成任务的返回结果,或者在超时时间内没有任务被执行完,直接抛出超时异常
//@return 第一个被线程池执行完成任务的结果
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
//@throws IllegalArgumentException 提交上来的任务集合大小为0,抛出IllegalArgumentException异常
//@throws ExecutionException 如果提交上来的任务集合中,没有一个任务被正确执行完成,会直接抛出ExecutionException异常
//@throws TimeoutException 在超时时间内没有一个任务执行完成,抛出超时异常
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}AbstractExecutorService
//提供线程池的任务转换、任务提交、以及线程池执行所有提交上来的任务或者其中一个任务的基础方法,但是AbstractExecutorService没有实现任务的执行execute方法,解耦任务的提交与每个任务将如何运行的机制
public abstract class AbstractExecutorService implements ExecutorService {
//传入Runnable类型的任务,以及存放返回结果的对象,将其适配成FutureTask类型的任务,返回适配后的FutureTask任务,对FutureTask不清楚的可以看下我的另一篇FutureTask的源码分析
//在FutureTask中会将Runnable类型的任务适配成Callable类型的任务
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
//使用FutureTask构造函数将Runnable类型任务和返回结果value封装成FutureTask任务
return new FutureTask<T>(runnable, value);
}
//传入Callable类型的任务,将其适配成FutureTask类型的任务,返回适配后的FutureTask任务,对FutureTask不清楚的可以看下我的另一篇FutureTask的源码分析
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
//使用FutureTask构造函数将Callable类型任务封装成FutureTask任务
return new FutureTask<T>(callable);
}
//提交没有返回结果的Runnable类型的任务到线程池
//@throws RejectedExecutionException 如果线程池任务队列满,并且线程队列也已经达到最大线程数,提交上来的任务无法被线程池处理,直接抛出RejectedExecutionException异常
//@throws NullPointerException 如果提交上来的任务为空,会抛出空指针异常
//@return 返回提交上来被线程池执行的任务,该任务没有返回结果,future.get()会返回null
public Future<?> submit(Runnable task) {
//如果提交上来的任务为空,抛出空指针异常
if (task == null) throw new NullPointerException();
//使用上面介绍的newTaskFor方法,将Runnable类型的任务封装成FutureTask类型的任务,没有返回结果的任务
RunnableFuture<Void> ftask = newTaskFor(task, null);
//执行提交上来的任务,AbstractExecutorService没有对execute方法进行实现,由子类进行实现,等下面介绍ThreadPoolExecutor会对该方法进行介绍
execute(ftask);
//返回提交上来被线程池执行的任务
return ftask;
}
//提交Runnable类型的任务到线程池,和传入存放返回结果的对象result
//@throws RejectedExecutionException 如果线程池任务队列满,并且线程队列也已经达到最大线程数,提交上来的任务无法被线程池处理,直接抛出RejectedExecutionException异常
//@throws NullPointerException 如果提交上来的任务为空,会抛出空指针异常
//@return 返回提交上来被线程池执行的任务,任务有返回结果,即result对象,result需要在自行在Runnable中使用,将结果存放在result中
public <T> Future<T> submit(Runnable task, T result) {
//如果提交上来的任务为空,抛出空指针异常
if (task == null) throw new NullPointerException();
//使用上面介绍的newTaskFor方法,将Runnable类型的任务封装成FutureTask类型的任务,没有返回结果的任务
RunnableFuture<T> ftask = newTaskFor(task, result);
//执行提交上来的任务,AbstractExecutorService没有对execute方法进行实现,由子类进行实现,等下面介绍ThreadPoolExecutor会对该方法进行介绍
execute(ftask);
//返回提交上来被线程池执行的任务
return ftask;
}
//提交有返回结果的Callable类型的任务到线程池
//@throws RejectedExecutionException 如果线程池任务队列满,并且线程队列也已经达到最大线程数,提交上来的任务无法被线程池处理,直接抛出RejectedExecutionException异常
//@throws NullPointerException 如果提交上来的任务为空,会抛出空指针异常
//@return 返回提交上来被线程池执行的任务,Callable类型的任务,call方法有任务执行的结果返回值
public <T> Future<T> submit(Callable<T> task) {
//如果提交上来的任务为空,抛出空指针异常
if (task == null) throw new NullPointerException();
//使用上面介绍的newTaskFor方法,将Callable类型的任务封装成FutureTask类型的任务,没有返回结果的任务
RunnableFuture<T> ftask = newTaskFor(task);
//执行提交上来的任务,AbstractExecutorService没有对execute方法进行实现,由子类进行实现,等下面介绍ThreadPoolExecutor会对该方法进行介绍
execute(ftask);
//返回提交上来被线程池执行的任务
return ftask;
}
//下面不管是支持超时参数还是支持参数的invokeAny方法,都是调doInvokeAny方法
//@param tasks 传入待执行的任务集合
//@param timed 是否支持超时
//@param nanos 超时时间
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws IllegalArgumentException 提交上来的任务集合大小为0,抛出IllegalArgumentException异常
//@throws ExecutionException 如果提交上来的任务集合中,在线程池中没有一个任务被正确执行完成,最后会直接抛出ExecutionException异常
//@throws TimeoutException 在超时时间内没有一个任务执行完成,抛出超时异常
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
//提交上来的任务集合为空,会抛出空指针异常
if (tasks == null)
//抛出空指针异常
throw new NullPointerException();
//获取提交上来的任务集合的任务数
int ntasks = tasks.size();
//提交上来的任务集合大小为0,抛出IllegalArgumentException异常
if (ntasks == 0)
//抛出IllegalArgumentException异常
throw new IllegalArgumentException();
//创建一个和提交上来的任务集合大小一样的Future的任务集合
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
//使用ExecutorCompletionService线程池和队列结合使用的类,使用当前线程池构造ExecutorCompletionService实例,不清楚ExecutorCompletionService的,可以看下我的另一篇对ExecutorCompletionService源码的分析
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
try {
ExecutionException ee = null;
//如果传入timed为true,即超时的执行队列中的任务,获取一个正确执行完成的任务,将传入的超时时间和当前时间加起来计算死亡时间,否则死亡时间0
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Iterator<? extends Callable<T>> it = tasks.iterator();
//提交上来的任务集合中的第一个任务提交到ExecutorCompletionService中,ExecutorCompletionService内部也是采用传入进去的线程池进行执行任务,保存未执行的任务,将提交到线程池执行的任务保存到Future集合中
futures.add(ecs.submit(it.next()));
//提交上来的未被执行的任务集合数减一
--ntasks;
//提交到线程池中执行的任务数赋值为1
int active = 1;
//死循环的获取第一个被正确执行
for (;;) {
//从ecs中的存放正确完成的任务的队列中获取第一个正确完成的任务
Future<T> f = ecs.poll();
//如果ecs队列中没有一个正确完成的任务
if (f == null) {
//判断提交上来的任务集合中是否还有未执行的任务
if (ntasks > 0) {
//如果提交上来的任务集合中有还未执行的任务,提交上来的未被执行的任务集合数减一
--ntasks;
//将传入进来未被执行的任务集合中的下一个任务提交到线程池执行,将该任务也保存到Future集合中
futures.add(ecs.submit(it.next()));
//提交到线程池中执行的任务数加1操作
++active;
}
//获取不到提交到ecs中的已正确完成的任务,并且提交上来的未被完成的任务集合全都提交到ecs中执行,并且ecs中的任务都被处理完,即没有一个正确完成的任务,直接退出循环
else if (active == 0)
//退出循环
break;
//如果传入进来的timed为true是支持超时的
else if (timed) {
//超时时间内在ecs中没有获取到被正确执行完成的任务
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
//在ecs中没有获取到已被正确执行完成的任务
if (f == null)
//抛出TimeoutException超时异常
throw new TimeoutException();
//死亡时间减去当前时间重新得到超时时间
nanos = deadline - System.nanoTime();
}
else
//否则阻塞的获取ecs存放已被执行完成的任务的队列中获取执行完成的任务,直到获取到,或者阻塞的线程被中断,抛出中断异常
f = ecs.take();
}
//如果从ecs存放已被执行完成的任务的队列中获取到执行完成的任务
if (f != null) {
//ecs线程池中执行的任务数(包括正在执行,和还未执行的任务)减1
--active;
try {
//从已完成的任务中获取任务的执行结果,在获取任务结果可能会抛出ExecutionException、CancellationException、InterruptedException,CancellationException异常也会被转换为ExecutionException,如果抛出InterruptedException会直接退出,如果在提交给线程池执行的待执行的任务集合中有一个任务被正确执行就不会抛出ExecutionException异常
return f.get();
} catch (ExecutionException eex) {
//将eex异常临时存放起来,如果在提交给线程池执行的待执行的任务集合中有一个任务被正确执行,该异常就不会被抛出
ee = eex;
} catch (RuntimeException rex) {//也会将运行时异常转换为ExecutionException异常临时存放起来
ee = new ExecutionException(rex);
}
}
}
//如果提交给线程池执行的待执行的任务集合中没有一个任务被正确执行
if (ee == null)
//构造ExecutionException异常
ee = new ExecutionException();
//直接抛出ExecutionException异常
throw ee;
} finally {
//将提交到ecs线程池中的还未被执行的任务中断取消,即任务状态从NEW-》INTERRUPTING-》INTERRUPTED
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
//线程池执行提交上来的任务集合的中的任务,一个一个任务执行,直到有个任务被正确执行完成,获取第一个正确执行完成任务的返回结果
//@return 第一个被线程池执行完成任务的结果
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
//@throws IllegalArgumentException 提交上来的任务集合大小为0,抛出IllegalArgumentException异常
//@throws ExecutionException 如果提交上来的任务集合中,没有一个任务被正确执行完成,会直接抛出ExecutionException异常
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
//不支持超时的调用上面介绍的doInvokeAny方法
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) { //doInvokeAny在支持超时时会抛出TimeoutException,为此需对其进行捕获
assert false;
//返回null
return null;
}
}
//线程池在超时时间内执行提交上来的任务集合的中的一个个任务,一个一个任务执行,直到有个任务完成,获取第一个完成任务的返回结果,或者在超时时间内没有任务被执行完,直接抛出超时异常
//@return 第一个被线程池执行完成任务的结果
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
//@throws IllegalArgumentException 提交上来的任务集合大小为0,抛出IllegalArgumentException异常
//@throws ExecutionException 如果提交上来的任务集合中,没有一个任务被正确执行完成,会直接抛出ExecutionException异常
//@throws TimeoutException 在超时时间内没有一个任务执行完成,抛出超时异常
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
//支持超时的调用上面介绍的doInvokeAny方法
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
//线程池执行提交上来的所有Callable类型的任务,返回所有正确执行完成的任务Future对象
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
//提交上来的任务集合为空,会抛出空指针异常
if (tasks == null)
//抛出空指针异常
throw new NullPointerException();
//创建一个和提交上来的任务集合大小一样的Future的任务集合
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
//提交上来的所有任务是否被执行完成的标志位
boolean done = false;
try {
//循环的遍历提交上来的任务集合
for (Callable<T> t : tasks) {
//使用上面介绍的newTaskFor方法,将Callable类型的任务封装成FutureTask类型的任务
RunnableFuture<T> f = newTaskFor(t);
//将FutureTask类型的任务保存到futures集合中
futures.add(f);
//执行提交上来的任务,AbstractExecutorService没有对execute方法进行实现,由子类进行实现,等下面介绍ThreadPoolExecutor会对该方法进行介绍
execute(f);
}
//循环的遍历保存到futures集合所有任务(提交到线程池执行的任务)
for (int i = 0, size = futures.size(); i < size; i++) {
//从futures集合中获取提交给线程池执行的任务
Future<T> f = futures.get(i);
//如果提交到线程池的任务还未完成,会阻塞当前线程
if (!f.isDone()) {
try {
//阻塞当前线程,从执行的任务中获取任务的执行结果,在获取任务结果可能会抛出ExecutionException、CancellationException、InterruptedException,如果抛出InterruptedException会直接退出,ExecutionException、CancellationException异常会被直接忽略掉
f.get();
} catch (CancellationException ignore) { //忽略任务的取消异常CancellationException
} catch (ExecutionException ignore) { //忽略任务的执行异常ExecutionException
}
}
}
//所有的任务执行完成
done = true;
//返回所有任务的Future对象,不管是执行异常的任务,还是取消、中断的任务
return futures;
} finally {
//如果当前线程在执行f.get(),当前线程被中断,直接抛出中断异常,done为false,所有的任务没有全部执行完成
if (!done)
//将提交到线程池中的还未被执行的任务中断取消,即任务状态从NEW-》INTERRUPTING-》INTERRUPTED
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
//线程池在超时时间执行提交上来的所有Callable类型的任务,返回所有任务Future对象(包括一些没有被执行任务的Future对象,执行完成的任务Future对象,正在被执行还未执行完成的Future对象,以及还未提交到线程池的Future对象,因为在线程池超时后,可能存在没有被执行的任务,或者还未执行完成的任务)
//@throws InterruptedException 等待获取任务执行完成结果的线程,等待的过程中被中断,直接抛出中断异常
//@throws NullPointerException 提交上来的任务集合为空,会直接抛出空指针异常
//@throws RejectedExecutionException 提交上来的任务集合中有个任务没法提交到线程池中,即线程池任务队列满,并且线程队列也已经达到最大线程数
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
//提交上来的任务集合为空,会抛出空指针异常
if (tasks == null)
//抛出空指针异常
throw new NullPointerException();
//将传入的超时参数转化为纳秒
long nanos = unit.toNanos(timeout);
//创建一个和提交上来的任务集合大小一样的Future的任务集合
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
//提交上来的所有任务是否被执行完成的标志位
boolean done = false;
try {
//循环的遍历提交上来的任务集合
for (Callable<T> t : tasks)
//将FutureTask类型的任务保存到futures集合中
futures.add(newTaskFor(t));
//将传入的超时时间和当前时间加起来计算死亡时间
final long deadline = System.nanoTime() + nanos;
//获取futures集合大小
final int size = futures.size();
//循环遍历Future的任务集合
for (int i = 0; i < size; i++) {
//执行提交上来的任务,AbstractExecutorService没有对execute方法进行实现,由子类进行实现,等下面介绍ThreadPoolExecutor会对该方法进行介绍
execute((Runnable)futures.get(i));
//死亡时间减去当前时间重新得到超时时间
nanos = deadline - System.nanoTime();
//如果超时时间小于等于0
if (nanos <= 0L)
//直接返回Future的任务集合,包括一些没有被执行任务的Future对象,执行完成的任务Future对象,正在被执行还未执行完成的Future对象,以及还未提交到线程池的Future对象
return futures;
}
//如果上面在超时时间内将Future的任务集合所有提交到线程池执行,循环遍历Future的任务集合,等待所有的任务执行完成
for (int i = 0; i < size; i++) {
//从Future的任务集合中获取每个Future任务
Future<T> f = futures.get(i);
//判断每个Future任务是否被执行完成
if (!f.isDone()) {
//如果超时时间小于等于0
if (nanos <= 0L)
//直接返回Future的任务集合,包括一些没有被执行任务的Future对象,执行完成的任务Future对象,正在被执行还未执行完成的Future对象,以及还未提交到线程池的Future对象
return futures;
try {
//阻塞当前线程,在超时的时间内从执行的任务中获取任务的执行结果,在获取任务结果可能会抛出ExecutionException、CancellationException、InterruptedException,如果抛出InterruptedException会直接退出,ExecutionException、CancellationException异常会被直接忽略掉
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {//忽略任务的取消异常CancellationException
} catch (ExecutionException ignore) {//忽略任务的执行异常ExecutionException
} catch (TimeoutException toe) { //从执行的任务中获取任务的执行结果,超时,捕获超时异常,直接返回Future的任务集合
return futures;
}
//死亡时间减去当前时间重新得到超时时间
nanos = deadline - System.nanoTime();
}
}
//所有的任务执行完成
done = true;
//返回所有任务的Future对象,不管是执行异常的任务,还是取消、中断的任务,完成的任务
return futures;
} finally {
//如果当前线程在执行f.get(),当前线程被中断,直接抛出中断异常,done为false,所有的任务没有全部执行完成
if (!done)
//将提交到线程池中的还未被执行的任务中断取消,即任务状态从NEW-》INTERRUPTING-》INTERRUPTED
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
}三、属性
//ctl存放线程池的状态和线程池的线程队列的线程数,高3位存放线程池的状态,低29位存放线程池线程队列中的线程数,ctl会在更新线程池状态和线程池的线程队列中的线程数使用到
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//29位存放线程池中的线程队列的线程数,即线程池中有多少个线程的位数
private static final int COUNT_BITS = Integer.SIZE - 3;
//线程池支持最大的线程数,低29位全为1
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//32位的高3位存放线程池的状态,RUNNING 高三位111 接受新任务和处理队列任务
private static final int RUNNING = -1 << COUNT_BITS;
//SHUTDOWN 高三位000 不接受新任务,但处理队列任务
private static final int SHUTDOWN = 0 << COUNT_BITS;
//STOP 高三位001 不接受新任务,不处理队列任务(将任务队列中所有未处理的任务全部取走),中断正在进行的任务
private static final int STOP = 1 << COUNT_BITS;
//TIDYING 高三位010 所有任务都结束,线程池里的线程队列为零,线程池转换到此状态,并且执行terminated()方法
private static final int TIDYING = 2 << COUNT_BITS;
//TERMINATED 高三位011 terminated()方法执行完成,会由TIDYING转换为TERMINATED状态
private static final int TERMINATED = 3 << COUNT_BITS;
//存放提交还未被线程池执行的任务,如果当前线程池中的线程队列数量小于核心线程数量,执行器总是优先创建一个线程执行任务,线程池采用的是生产者消费者的模式,而不是采用从线程队列中取一个空闲线程执行任务。线程队列中的线程执行完第一个任务,就会死循环的从任务队列中获取任务执行,如果出现异常或者非核心线程从任务队列中获取不到任务,线程会从线程队列中移除,如果小于核心线程数,会重新创建一个新的线程加入到线程队列中
private final BlockingQueue<Runnable> workQueue;
//独占锁,用来保证操作成员变量的并发安全问题,主要是来保证下面的workers、largestPoolSize、completedTaskCount属性,ctl、workQueue属性本身就是线程安全的,无需使用独占锁进行保证,不清楚的可以看下我的另一篇对ReentrantLock的源码分析
private final ReentrantLock mainLock = new ReentrantLock();
//线程池中的线程队列,即工作线程集合,Worker中持有线程thread变量
private final HashSet<Worker> workers = new HashSet<Worker>();
//等待线程池完全停止的条件变量termination
private final Condition termination = mainLock.newCondition();
//线程池中的线程队列曾经拥有过的最大工作线程个数,需由mainLock保证线程安全
private int largestPoolSize;
//线程池完成过任务的总个数,需由mainLock保证线程安全
private long completedTaskCount;
//创建工作线程的工厂类
private volatile ThreadFactory threadFactory;
//任务提交到线程池,当线程池中的任务队列已满,并且线程队列也已经到最大线程个数,线程池如何处理该任务,直接丢弃,还是抛出异常,还是有提交的线程直接执行,或者忽略不做任何处理
private volatile RejectedExecutionHandler handler;
//工作线程空闲的超时时间,如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程,如果allowCoreThreadTimeOut为true也允许回收空闲的核心线程
private volatile long keepAliveTime;
//是否允许核线程池线程队列中的核心线程获取不到任务,超时退出线程队列
private volatile boolean allowCoreThreadTimeOut;
//线程池中线程队列的核心线程个数,corePoolSize可以等于0,但是不能小于0,线程队列的核心线程就是线程池能够维持的常用工作线程,当工作线程没有可执行任务空闲时,它不会被销毁,而是在等待。但是如果设置allowCoreThreadTimeOut为true,那么线程队列的核心工作线程也是会被销毁
private volatile int corePoolSize;
//线程池中线程队列的最大线程个数,不能小于等于0,就是当线程队列的核心工作线程不够用,且任务队列也已经满了,不能添加新的任务了,那么就要开启新的工作线程来执行任务
private volatile int maximumPoolSize;
//默认的拒绝策略,抛出RejectedExecutionException异常,下面在介绍内部类时会对其他几种的拒绝策略进行详细的介绍
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
四、构造函数
/**
* 传入核心线程数、线程队列中的最大线程个数、时间单位、工作线程空闲的超时时间(如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程)、存放未被线程池马上执行的任务队列构造ThreadPoolExecutor线程池对象
* @param corePoolSize 线程队列的核心线程就是线程池能够维持的工作线程,当工作线程没有可执行任务空闲时,它不会被销毁,而是在等待, 除非 {@code allowCoreThreadTimeOut} 被设置为true
* @param maximumPoolSize 线程池允许线程队列的最大线程数,就是当线程队列的核心工作线程不够用,且任务队列也已经满了,不能添加新的任务了,那么就要开启新的工作线程来执行任务
* @param keepAliveTime 工作线程空闲的超时时间,如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程,如果allowCoreThreadTimeOut为true也允许回收空闲的核心线程
* @param keepAliveTime的时间单位
* @param workQueue 存放提交还未被线程池执行的任务,如果当前线程池中的线程队列数量小于核心线程数量,执行器总是优先创建一个线程执行任务,线程池采用的是生产者消费者的模式,而不是采用从线程队列中取一个空闲线程执行任务。线程队列中的线程执行完第一个任务,就会死循环的从任务队列中获取任务执行,如果出现异常或者非核心线程从任务队列中获取不到任务,线程会从线程队列中移除,如果小于核心线程数,会重新创建一个新的线程加入到线程队列中
* @throws IllegalArgumentException 如果出现以下其中一种都会IllegalArgumentException异常:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException 如果传入的workQueue存放未被执行的任务队列为空,抛出空指针异常
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
//调用下面的构造函数,传入默认的构造线程工厂和默认的任务拒绝策略
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/**
* 传入核心线程数、线程队列中的最大线程个数、时间单位、工作线程空闲的超时时间(如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程)、存放未被线程池马上执行的任务队列、创建线程池线程的线程工厂构造ThreadPoolExecutor线程池对象
* @param corePoolSize 线程队列的核心线程就是线程池能够维持的工作线程,当工作线程没有可执行任务空闲时,它不会被销毁,而是在等待, 除非 {@code allowCoreThreadTimeOut} 被设置为true
* @param maximumPoolSize 线程池允许线程队列的最大线程数,就是当线程队列的核心工作线程不够用,且任务队列也已经满了,不能添加新的任务了,那么就要开启新的工作线程来执行任务
* @param keepAliveTime 工作线程空闲的超时时间,如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程,如果allowCoreThreadTimeOut为true也允许回收空闲的核心线程
* @param keepAliveTime的时间单位
* @param workQueue 存放提交还未被线程池执行的任务,如果当前线程池中的线程队列数量小于核心线程数量,执行器总是优先创建一个线程执行任务,线程池采用的是生产者消费者的模式,而不是采用从线程队列中取一个空闲线程执行任务。线程队列中的线程执行完第一个任务,就会死循环的从任务队列中获取任务执行,如果出现异常或者非核心线程从任务队列中获取不到任务,线程会从线程队列中移除,如果小于核心线程数,会重新创建一个新的线程加入到线程队列中
* @param threadFactory 线程工厂被用来为线程池创建新的线程,可以在线程工厂里对线程命名业务化的语义,设置是否是守护线程等
* @throws IllegalArgumentException 如果出现以下其中一种都会IllegalArgumentException异常:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException 如果传入的workQueue存放未被执行的任务队列为空,或者创建线程的工厂为空,抛出空指针异常
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
//调用下面的构造函数,传入默认的任务拒绝策略
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
/**
* 传入核心线程数、线程队列中的最大线程个数、时间单位、工作线程空闲的超时时间(如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程)、存放未被线程池马上执行的任务队列、任务拒绝策略构造ThreadPoolExecutor线程池对象
* @param corePoolSize 线程队列的核心线程就是线程池能够维持的工作线程,当工作线程没有可执行任务空闲时,它不会被销毁,而是在等待, 除非 {@code allowCoreThreadTimeOut} 被设置为true
* @param maximumPoolSize 线程池允许线程队列的最大线程数,就是当线程队列的核心工作线程不够用,且任务队列也已经满了,不能添加新的任务了,那么就要开启新的工作线程来执行任务
* @param keepAliveTime 工作线程空闲的超时时间,如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程,如果allowCoreThreadTimeOut为true也允许回收空闲的核心线程
* @param keepAliveTime的时间单位
* @param workQueue 存放提交还未被线程池执行的任务,如果当前线程池中的线程队列数量小于核心线程数量,执行器总是优先创建一个线程执行任务,线程池采用的是生产者消费者的模式,而不是采用从线程队列中取一个空闲线程执行任务。线程队列中的线程执行完第一个任务,就会死循环的从任务队列中获取任务执行,如果出现异常或者非核心线程从任务队列中获取不到任务,线程会从线程队列中移除,如果小于核心线程数,会重新创建一个新的线程加入到线程队列中
* @param handler 任务提交到线程池,当线程池中的任务队列已满,并且线程队列也已经到最大线程个数,线程池如何处理该任务,直接丢弃,还是抛出异常,还是有提交的线程直接执行,或者忽略不做任何处理
* @throws IllegalArgumentException 如果出现以下其中一种都会IllegalArgumentException异常:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException 如果传入的workQueue存放未被执行的任务队列为空,或者任务拒绝策略为空,抛出空指针异常
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
//调用下面的构造函数,传入默认的构造线程工厂
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
//上面三个构造函数都是调用此构造函数
/**
* 传入核心线程数、线程队列中的最大线程个数、时间单位、工作线程空闲的超时时间(如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程)、存放未被线程池马上执行的任务队列、创建线程池线程的线程工厂构造ThreadPoolExecutor线程池对象
* @param corePoolSize 线程队列的核心线程就是线程池能够维持的工作线程,当工作线程没有可执行任务空闲时,它不会被销毁,而是在等待, 除非 {@code allowCoreThreadTimeOut} 被设置为true
* @param maximumPoolSize 线程池允许线程队列的最大线程数,就是当线程队列的核心工作线程不够用,且任务队列也已经满了,不能添加新的任务了,那么就要开启新的工作线程来执行任务
* @param keepAliveTime 工作线程空闲的超时时间,如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程,如果allowCoreThreadTimeOut为true也允许回收空闲的核心线程
* @param keepAliveTime的时间单位
* @param workQueue 存放提交还未被线程池执行的任务,如果当前线程池中的线程队列数量小于核心线程数量,执行器总是优先创建一个线程执行任务,线程池采用的是生产者消费者的模式,而不是采用从线程队列中取一个空闲线程执行任务。线程队列中的线程执行完第一个任务,就会死循环的从任务队列中获取任务执行,如果出现异常或者非核心线程从任务队列中获取不到任务,线程会从线程队列中移除,如果小于核心线程数,会重新创建一个新的线程加入到线程队列中
* @param threadFactory 线程工厂被用来为线程池创建新的线程,可以在线程工厂里对线程命名业务化的语义,设置是否是守护线程等
* @param handler 任务提交到线程池,当线程池中的任务队列已满,并且线程队列也已经到最大线程个数,线程池如何处理该任务,直接丢弃,还是抛出异常,还是有提交的线程直接执行,或者忽略不做任何处理
* @throws IllegalArgumentException 如果出现以下其中一种都会IllegalArgumentException异常:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException 如果传入的workQueue存放未被执行的任务队列为空,或者创建线程的工厂、任务拒绝策略为空,抛出空指针异常
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
//如果核心线程数小于0,或者最大线程数小于等于0,或者最大线程数小于核心线程数,或者线程空闲的超时时间小于0,抛出IllegalArgumentException异常
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
//传入的存放未被执行的任务队列为空、或者创建线程的工厂为空、或者任务的拒绝策略为空,抛出NullPointerException异常
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
//ThreadPoolExecutor实例的属性corePoolSize赋值为传入进来的核心线程数
this.corePoolSize = corePoolSize;
//ThreadPoolExecutor实例的属性maximumPoolSize赋值为传入进来的最大线程数
this.maximumPoolSize = maximumPoolSize;
//ThreadPoolExecutor实例的属性workQueue赋值为传入进来的存放未被执行的任务队列
this.workQueue = workQueue;
//ThreadPoolExecutor实例的属性keepAliveTime 赋值为传入进来的线程空闲的超时时间,如果allowCoreThreadTimeOut为false针对超过核心池数量的工作线程,如果allowCoreThreadTimeOut为true也允许回收空闲的核心线程
this.keepAliveTime = unit.toNanos(keepAliveTime);
//ThreadPoolExecutor实例的属性threadFactory赋值为传入进来的创建线程的工厂
this.threadFactory = threadFactory;
//ThreadPoolExecutor实例的属性threadFactory赋值为传入进来的任务的拒绝策略
this.handler = handler;
}五、内部类
- Worker内部类
//工作线程Worker,线程队列中的成员变量,如果提交上来的任务,线程队列的线程数小于核心线程数,创建一个工作线程Worker,将它添加到线程集合worker中,或者超过线程队列的核心线程数,并且任务队列也已满,创建一个工作线程Worker,将它添加到线程集合worker中,使用mainLock独占锁保证成员变量workers的并发安全问题 //使用AQS的独占模式来判断当前工作线程Worker是否处于空闲状态,目的是为了后面中断执行的工作线程,下面会详细介绍 //AbstractQueuedSynchronizer不清楚的可以看下我的另一篇对AQS的源码分析,Worker也实现Runnable,本身也是个任务 private final class Worker extends AbstractQueuedSynchronizer implements Runnable { private static final long serialVersionUID = 6138294804551838833L; //Worker拥有的工作线程 final Thread thread; //Worker拥有的第一个任务,初始化的时候赋值,在预先初始化核心工作线程时,firstTask会传null Runnable firstTask; //工作线程Worker完成的任务数量 volatile long completedTasks; //Worker的构造函数,传入第一个被该工作线程执行的任务,在预先初始化核心工作线程时,firstTask会传null Worker(Runnable firstTask) { //首先将AQS的属性state,即当前工作线程的状态,设置为-1,禁止中断请求,直到工作线程执行过,执行run方法中的runWorker,即在下面Worker类中的interruptIfStarted中断工作线程,工作线程的状态只能在大于等于0的时候才能响应中断 setState(-1); //该工作线程要执行的第一个任务,可能为null this.firstTask = firstTask; //使用构造线程的工厂创建Thread线程对象,将Worker做为参数传入Thread中,当Thread执行启动start,执行Thread.run方法会执行Worker的run方法 this.thread = getThreadFactory().newThread(this); } //Worker重写Runnable中的run方法,所以当thread启动后,thread的run方法会执行Worker的run方法 public void run() { //将自身Worker做为参数传入runWorker方法中,下面会介绍runWorker方法 runWorker(this); } //判断当前线程是否空闲,根据AQS的独占模式来判断当前工作线程Worker是否空闲 protected boolean isHeldExclusively() { //Worker的独占锁被持有,表明Worker处于工作状态 return getState() != 0; } //尝试获取Worker独占锁,tryAcquire在AQS中是个模板方法,直接抛出不支持异常,Worker对tryAcquire进行重写,在下面的lock中的acquire会调用tryAcquire进行获取独占锁,对AQS不清楚的可以看下我的另一篇AQS源码分析 protected boolean tryAcquire(int unused) { // 如果通过CAS函数,可以将state值从0改变成1,表示获取独占锁成功。 // 否则独占锁被其他线程持有。 if (compareAndSetState(0, 1)) { //如果获取独占锁成功,将当前线程设置为持有独占锁的线程 setExclusiveOwnerThread(Thread.currentThread()); //返回占有Worker独占锁成功 return true; } //返回占有Worker独占锁失败 return false; } //尝试释放独占锁,传入的参数没有被使用到 protected boolean tryRelease(int unused) { //将持有Worker独占锁的线程设置为空,即属性exclusiveOwnerThread赋值为null setExclusiveOwnerThread(null); //将Worker独占锁的状态设置为0,释放独占锁,即将AQS的属性state设置为0,状态0表示独占锁Worker处于空闲状态 setState(0); //返回释放独占锁Worker成功 return true; } //获取Worker实例独占锁,不响应中断,直到获取独占锁成功,获取的过程中,线程可能会进入等待状态,根据前置节点进行判断, public void lock() { //调用Worker从AQS继承下来的acquire方法,对AQS不清楚的可以看下我的另一篇AQS源码分析 acquire(1); } //尝试获取Worker实例独占锁,如果锁被别的线程持有,就直接返回false,表示获取独占锁失败 public boolean tryLock() { //调用上面介绍的tryAcquire方法尝试获取独占锁 return tryAcquire(1); } //释放Worker独占锁 public void unlock() { //调用Worker从AQS继承下来的release方法,不清楚的可以看下另一篇AQS源码分析对此方法的介绍 release(1); } //判断当前线程Worker是否空闲,即独占锁是否有被其他线程占有 public boolean isLocked() { return isHeldExclusively(); } //如果Worker的工作线程thread已经开启,即执行过runWorker方法,响应中断请求,将Worker的工作线程thread状态设置为中断 void interruptIfStarted() { Thread t; //在Worker的构造函数将状态设置为-1,在runWorker中调用unlock将状态设置为0,表示Worker的工作线程已经启动 //Worker的状态大于等于0,表示Worker的线程Thread已经工作,并且Worker的线程Thread不能为空,并且Worker的线程Thread没有被中断 if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { //将Worker的线程Thread状态设置为中断 t.interrupt(); } catch (SecurityException ignore) { } } } } - CallerRunsPolicy内部类
/** * 一个处理无法被线程池执行的任务 * @param r 可运行任务要求被执行 * @param executor 执行任务的线程池 * @throws RejectedExecutionException 如果没有补救措施,直接抛出RejectedExecutionException */ public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); } //将任务分给提交任务的线程来执行 public static class CallerRunsPolicy implements RejectedExecutionHandler { //无参的构造方法 public CallerRunsPolicy() { } //无法被线程池执行的任务的处理方法 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //判断传入进来的线程池是否关闭,如果关闭是不接收新的任务,线程池状态不清楚的可以看上面的简介 if (!e.isShutdown()) { //直接执行提交上来任务的run方法 r.run(); } } } - AbortPolicy内部类
//直接抛出RejectedExecutionException异常 public static class AbortPolicy implements RejectedExecutionHandler { //无参的构造方法 public AbortPolicy() { } //无法被线程池执行的任务的处理方法 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //直接抛出RejectedExecutionException异常 throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } } - DiscardPolicy内部类
//将任务直接丢弃,不做任何处理 public static class DiscardPolicy implements RejectedExecutionHandler { //无参的构造方法 public DiscardPolicy() { } //无法被线程池执行的任务的处理方法 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //不做任何处理 } } - DiscardOldestPolicy内部类
//丢弃任务队列中最老的任务,即队列中第一个任务 public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //判断传入进来的线程池是否关闭,如果关闭是不接收新的任务,线程池状态不清楚的可以看上面的简介 if (!e.isShutdown()) { //从任务队列中获取第一个任务(最老的任务),即从任务队列中移除 e.getQueue().poll(); //线程池重新执行该任务,线程池的execute方法下面会进行介绍 e.execute(r); } } }
六、核心参数
//设置创建工作线程的工厂类,属性threadFactory加上volatile,是为了保证,在将工作线程的工厂类设置进去,对其他使用工厂的线程可见,到时会写一篇volatile,锁,final的文章
public void setThreadFactory(ThreadFactory threadFactory) {
//如果传入进来的创建工作线程的工厂类为空,直接抛出空指针异常
if (threadFactory == null)
//抛出空指针异常
throw new NullPointerException();
//否则的话将ThreadPoolExecutor实例属性threadFactory赋值为传入进来的创建工作线程的工厂类
this.threadFactory = threadFactory;
}
//获取ThreadPoolExecutor实例创建工作线程的工厂属性threadFactory,如果在构造ThreadPoolExecutor没有传入工厂实例,返回默认的工厂类实例
public ThreadFactory getThreadFactory() {
//返回创建工作线程的工厂属性threadFactory
return threadFactory;
}
//设置任务无法提交到线程池执行的拒绝策略,当线程池中的任务队列已满,并且线程队列也已经到最大线程个数,线程池如何处理该任务,直接丢弃,还是抛出异常,还是有提交的线程直接执行,或者忽略不做任何处理,四种拒绝策略可以看上面内部类中对这四种策略的介绍
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
//传入进来的拒绝策略handler为空,直接抛出空指针异常
if (handler == null)
//抛出空指针异常
throw new NullPointerException();
//将ThreadPoolExecutor实例属性handler赋值为传入进来的拒绝策略实例
this.handler = handler;
}
//获取ThreadPoolExecutor实例任务无法提交到线程池执行的拒绝策略属性handler,如果在构造ThreadPoolExecutor没有传入拒绝策略实例,返回默认的拒绝策略实例
public RejectedExecutionHandler getRejectedExecutionHandler() {
//返回创建工作线程的工厂属性handler
return handler;
}
//重新设置线程池中线程队列的核心线程个数
public void setCorePoolSize(int corePoolSize) {
//传入进来的参数小于0,抛出IllegalArgumentException异常
if (corePoolSize < 0)
throw new IllegalArgumentException();
//新设置的核心线程个数减去原来的核心线程个数,是为了新设置的核心线程数比原先多,并且队列不为空,线程队列中多加核心线程
int delta = corePoolSize - this.corePoolSize;
//将线程池的corePoolSize参数重新赋值为传入进来的核心线程数
this.corePoolSize = corePoolSize;
//判断线程队列中的线程数是否大于核心线程数,如果大于,中断所有空闲线程
if (workerCountOf(ctl.get()) > corePoolSize)
//中断所有空闲线程,目的是为了唤醒那些等待任务队列中的任务,下面会对interruptIdleWorkers方法进行介绍
interruptIdleWorkers();
//如果传入进来的核心线程参数大于原先线程池线程队列的核心线程数,并且任务队列不为空,新增核心线程数
else if (delta > 0) {
//获取核心线程数和任务队列大小的小值
int k = Math.min(delta, workQueue.size());
//循环在线程队列中新增核心线程数,直到任务队列为空,或者在线程队列中核心线程失败,即线程队列中的线程数已经超过或等于核心线程数
while (k-- > 0 && addWorker(null, true)) {
//如果任务队列为空,直接退出循环
if (workQueue.isEmpty())
//退出循环
break;
}
}
}
//获取线程池线程队列中的核心线程数
public int getCorePoolSize() {
//返回线程池线程队列中的核心线程数
return corePoolSize;
}
//预先启动一个核心线程,但是要是在创建线程池时传入的核心线程数corePoolSize为0,不会创建一个核心的线程,或者线程队列中的线程数已经超过核心线程数,也不会预先创建一个核心线程
//返回是否预先启动核心线程成功
public boolean prestartCoreThread() {
//如果线程池线程队列中的线程,即线程队列中的线程还未到核心线程数,
return workerCountOf(ctl.get()) < corePoolSize &&
//在线程队列中多加个工作线程,第二个参数为true,要在同步队列中加入核心线程,下面会对此方法进行介绍
addWorker(null, true);
}
//一定会在同步队列中加入一个核心线程,除非线程队列中的线程数已经达到核心线程数
void ensurePrestart() {
//获取线程池线程队列的线程数
int wc = workerCountOf(ctl.get());
//如果线程池线程队列的线程数小于核心线程数,
if (wc < corePoolSize)
//在线程队列中多加个工作线程,第二个参数为true,要在同步队列中加入核心线程,下面会对此方法进行介绍
addWorker(null, true);
//如果在构造线程池时,传入的核心线程数corePoolSize等于0,并且线程池线程队列中没有工作线程
else if (wc == 0)
//因为核心线程数corePoolSize为0,为此调用addWorker方法,传入false,在线程队列中加入非核心线程,确保线程队列中至少有一个线程
addWorker(null, false);
}
//预先启动所有的核心线程,但是要是在创建线程池时传入的核心线程数corePoolSize为0,不会创建一个核心的线程
//返回往线程队列中加入多少个核心线程
public int prestartAllCoreThreads() {
//线程队列中加入多少个核心线程
int n = 0;
//循环创建核心线程,并加入到线程队列,直到线程队列的工作线程已经达到核心线程数
while (addWorker(null, true))
//创建核心线程的个数做加一操作
++n;
//返回往线程队列中加入多少个核心线程
return n;
}
//获取是否允许线程池线程队列中的核心线程在任务队列中空闲的时候自动退出线程队列
public boolean allowsCoreThreadTimeOut() {
//返回是否允许核心线程获取不到任务队列任务,退出线程队列
return allowCoreThreadTimeOut;
}
//重新设置是否允许核线程池线程队列中的核心线程获取不到任务,超时退出线程队列
public void allowCoreThreadTimeOut(boolean value) {
//如果allowCoreThreadTimeOut为true,那么工作线程空闲的超时keepAliveTime不能小于等于0,否则会直接抛出IllegalArgumentException异常
if (value && keepAliveTime <= 0)
//如果value为true,并且keepAliveTime小于等于0抛出IllegalArgumentException异常
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
//如果传入进来的参数和线程池原先的allowCoreThreadTimeOut不相等
if (value != allowCoreThreadTimeOut) {
//重新设置allowCoreThreadTimeOut的值,赋值为传入进来的参数
allowCoreThreadTimeOut = value;
//如果传入进来的参数为true,即允许核心线程在空闲时退出
if (value)
//中断所有空闲线程,目的是为了唤醒那些等待任务队列中的线程,然后在一定的时间内获取不到任务退出线程池,下面会对interruptIdleWorkers方法进行介绍
interruptIdleWorkers();
}
}
//重新设置线程池线程队列中允许的最大线程数,最大的线程数不能小于等于0,核心线程数corePoolSize可以等于0
public void setMaximumPoolSize(int maximumPoolSize) {
//如果传入进来的最大线程数小于等于0,抛出IllegalArgumentException异常
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
//抛出IllegalArgumentException异常
throw new IllegalArgumentException();
//将线程池最大线程数的maximumPoolSize属性赋值为传入进来的maximumPoolSize参数
this.maximumPoolSize = maximumPoolSize;
//如果线程池线程队列中工作线程大于最大的线程数,中断空闲的线程,包括那些等待任务的线程,将其退出线程队列中
if (workerCountOf(ctl.get()) > maximumPoolSize)
//中断所有空闲线程,目的是为了唤醒那些等待任务队列中的线程,然后在一定的时间内获取不到任务退出线程池,下面会对interruptIdleWorkers方法进行介绍
interruptIdleWorkers();
}
//获取线程池线程队列允许的最大线程数
public int getMaximumPoolSize() {
//返回线程池线程队列允许的最大线程数
return maximumPoolSize;
}
//传入时间单位获取工作线程空闲的超时时间,其实是获取任务队列中任务的超时时间,如果在超时时间获取不到任务,线程会退出,如果allowCoreThreadTimeOut为false针对超过核心工作线程数量的工作线程,如果allowCoreThreadTimeOut为true也允许回收空闲的核心线程
public long getKeepAliveTime(TimeUnit unit) {
//返回将纳秒keepAliveTime转换为传入的时间单位值
return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
}
//重新设置线程池工作线程空闲的超时时间
public void setKeepAliveTime(long time, TimeUnit unit) {
//如果传入的超时时间小于0,直接抛出IllegalArgumentException异常
if (time < 0)
//抛出IllegalArgumentException异常
throw new IllegalArgumentException();
//如果传入的超时参数为0,并且allowsCoreThreadTimeOut参数为true,直接抛出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;
//将线程池的超时参数keepAliveTime赋值为传入进来的超时参数
this.keepAliveTime = keepAliveTime;
//如果传入进来的超时参数小于原先的超时参数,中断所有空闲线程
if (delta < 0)
//中断所有空闲线程,目的是为了唤醒那些等待任务队列中的线程,然后在一定的时间内获取不到任务退出线程池,下面会对interruptIdleWorkers方法进行介绍
interruptIdleWorkers();
}七、执行任务
//提交任务给线程池执行
public void execute(Runnable command) {
//传入的Runnable类型的任务为空直接抛出NullPointerException异常
if (command == null)
//抛出空指针异常
throw new NullPointerException();
//获取ctl的值,ctl的值高三位存放线程池的状态,低29位存放工作线程的个数,即线程队列中的线程数
int c = ctl.get();
//如果线程队列中的线程数小于核心线程数
if (workerCountOf(c) < corePoolSize) {
//创建核心工作线程将其核心工作线程加入到线程队列中,如果成功直接退出
if (addWorker(command, true))
//直接退出
return;
//如果核心线程加入线程队列失败,表明有其他核心线程先加入线程队列中,线程队列中已经有达到核心线程数的线程,重新获取ctl值
c = ctl.get();
}
//先判断线程池是否运行,即线程池状态RUNNING,将要执行的任务加入到任务队列中
if (isRunning(c) && workQueue.offer(command)) {
//重新获取ctl值,ctl的值高三位存放线程池的状态,低29位存放工作线程的个数,即线程队列中的线程数
int recheck = ctl.get();
//重新判断线程池的状态,如果线程池已经不是运行状态,将任务从任务队列中移除,并且调用reject方法执行拒绝任务的策略
if (! isRunning(recheck) && remove(command))
//执行线程池任务的拒绝策略
reject(command);
//如果线程池的工作线程为空,即线程队列没有工作线程
else if (workerCountOf(recheck) == 0)
//有可能传入进来的corePoolSize等于0,为此需要调用addWorker往线程队列中加工作线程
addWorker(null, false);
}
//如果线程池的线程队列中的线程已经大于等于核心线程数,并且线程中的任务队列也已经满,使用addWorker往线程队列中加入非核心的工作线程,但小于线程池的最大线程数
else if (!addWorker(command, false))
//如果创建非核心线程到线程队列中失败,即线程队列中线程数已经达到最大线程数,执行线程池的拒绝策略,拒绝策略不清楚的可以看上面对四种策略的介绍
reject(command);
}
/**
* 创建工作线程和将其新建的工作线程加入线程队列中
*
* @param firstTask 工作线程第一个执行的任务,有可能为空,因为有可能是预先启动核心线程,也可能线程池SHUTDOWN状态,但是任务队列还有任务,工作线程第一个执行执行的任务也可能为空
* @param core 创建的线程是否是核心工作线程的标识,如果是线程池线程队列已经有核心线程数目的线程,返回创建工作线程和加入线程队列中失败
* @return 是否创建工作线程和将其新建的工作线程加入线程队列中成功
*/
private boolean addWorker(Runnable firstTask, boolean core) {
//外层循环退出的标志位
retry:
for (;;) {
//获取ctl的值,ctl的值高三位存放线程池的状态,低29位存放工作线程的个数,即线程队列中的线程数
int c = ctl.get();
//从ctl值的高三位获取线程池的状态
int rs = runStateOf(c);
//如果线程池的状态大于等于SHUTDOWN,即线程池至少已经关闭,如果线程池的状态等于SHUTDOWN,并且任务队列也为空,直接返回失败
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
//死循环的线程队列中的工作线程数进行加1操作
for (;;) {
//获取线程池线程队列的工作线程数
int wc = workerCountOf(c);
//如果线程池线程队列的工作线程数大于线程池支持最大的线程数,或者core传入为true,线程队列中的已有的工作线程数大于等于核心线程数,也会直接返回失败,或者core传入为false,线程队列中的已有的工作线程数大于等于最大线程数
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//ctl进行加1操作,即线程池中的工作线程数加1操作
if (compareAndIncrementWorkerCount(c))
//退出外层循环
break retry;
//如果线程数加1操作失败,即有其他工作线程加入线程队列中,重新获取ctl值
c = ctl.get();
//如果线程池的状态改变
if (runStateOf(c) != rs)
//跳到外层循环,重新进行循环
continue retry;
}
}
//工作线程是否成功启动的标志位
boolean workerStarted = false;
//工作线程是否成功加入到线程队列中的标志位
boolean workerAdded = false;
Worker w = null;
try {
//传入firstTask,工作第一个执行的任务创建工作线程,Worker可以看上面对内部类的介绍
w = new Worker(firstTask);
//获取工作线程中的线程对象
final Thread t = w.thread;
if (t != null) {
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因为需要将新建的工作线程Worker加入到线程队列Workers中,Workers集合不是线程安全的,还有需要对线程池的largestPoolSize(线程池曾经同时存在的最大线程数)进行操作
mainLock.lock();
try {
//从ctl值中获取线程池的状态
int rs = runStateOf(ctl.get());
//如果线程池RUNNING状态,或者线程池已关闭,并且传入进来的firstTask为空,即第一个被新建工作线程执行的任务为空,才会将新建的工作线程加入到线程队列中
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//如果工作线程中的线程对象已经启动,抛出IllegalThreadStateException异常
if (t.isAlive())
throw new IllegalThreadStateException();
//将工作线程加入到线程队列中
workers.add(w);
//获取工作队列中的线程数
int s = workers.size();
//如果当前工作队列中的线程数大于曾经线程池曾经同时存在的最大线程数
if (s > largestPoolSize)
//对largestPoolSize重新赋值为当前队列中的线程数
largestPoolSize = s;
//工作线程成功加入到线程队列中
workerAdded = true;
}
} finally {
//finally中释放独占锁
mainLock.unlock();
}
//如果新建的工作线程成功加入到线程池的线程队列中
if (workerAdded) {
//启动工作线程对应的线程
t.start();
//工作线程对应的线程成功启动
workerStarted = true;
}
}
} finally {
//如果工作线程对应的线程没有启动成功
if (! workerStarted)
//将加入到线程队列中的工作线程从线程队列中移除,线程池中的线程队列中的工作线程数减1操作
addWorkerFailed(w);
}
//返回新建工作线程对应的线程是否启动成功的标志位
return workerStarted;
}
//任务的被线程池拒绝(即线程池中的线程队列已经达到最大线程数,并且任务队列也已经满)的调用方法,会调用线程池的拒绝策略
final void reject(Runnable command) {
//执行线程池拒绝策略的rejectedExecution方法,对拒绝策略不清楚的可以看下上面内部类对四种拒绝策略的介绍
handler.rejectedExecution(command, this);
}
private void addWorkerFailed(Worker w) {
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因为需要将传入进来的工作线程Worker从线程队列Workers中移除,Workers集合不是线程安全的
mainLock.lock();
try {
//如果传入进来的工作线程不是空
if (w != null)
//从线程队列中移除传入进来的工作线程
workers.remove(w);
//线程池中的线程队列工作线程数做减1操作
decrementWorkerCount();
//尝试结束线程池,看下面对tryTerminate方法的介绍
tryTerminate();
} finally {
//finally中释放独占锁
mainLock.unlock();
}
}
final void tryTerminate() {
for (;;) {
//获取ctl的值
int c = ctl.get();
//如果线程池状态是RUNNING(运行中),或者线程池的状态至少是TIDYING,或者线程的已经关闭SHUTDOWN,并且线程队列不为空
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
//满足上面其中一种条件直接退出
return;
//获取线程池中的线程队列的工作线程数,如果工作线程数不等于0,中断一个空闲的线程
if (workerCountOf(c) != 0) {
//中断空闲线程,ONLY_ONE为true,中断一个空闲线程
interruptIdleWorkers(ONLY_ONE);
//直接退出
return;
}
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因为使用termination条件变量通知所有等待线程池结束的线程,条件变量需要在锁的独占锁的条件下才能使用
mainLock.lock();
try {
//将表示线程池状态和线程池中的线程队列的ctl使用cas重新设置为状态为TIDYING,线程队列中的线程数为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
//terminated()方法是个空方法,模板方法,子类可以重写实现,比如做一些线程池停止中的清除操作
terminated();
} finally {
//将线程池的状态由TIDYING转换为TERMINATED状态
ctl.set(ctlOf(TERMINATED, 0));
//通知所有等待线程池结束的线程
termination.signalAll();
}
//直接退出
return;
}
} finally {
//finally中释放独占锁
mainLock.unlock();
}
}
}
//由工作线程Worker中的run方法调用,Worker也是Runnable的实现类,为此在Worker中的线程Thread运行时,会调用Worker的run方法,Worker方法会调用runWorker方法
final void runWorker(Worker w) {
//获取当前线程
Thread wt = Thread.currentThread();
//获取工作线程中的一个需要执行的任务,firstTask可能会空
Runnable task = w.firstTask;
//将工作线程Worker中firstTask属性置为空
w.firstTask = null;
//允许被中断,创建Worker时,Worker的状态为-1,不允许中断,直到Worker第一次运行run方法,即runWorker方法
w.unlock();
//工作线程是否突然结束,即运行用户任务出现编译时异常
boolean completedAbruptly = true;
try {
//工作线程中的第一个任务不为空,或者从任务队列中获取的任务不为空
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做一些预处理操作,比如记录日志等,是个空方法子类可以自行实现,即可扩展性
beforeExecute(wt, task);
//不管是异常还是错误,统一抛出Throwable异常
Throwable thrown = null;
try {
//运行用户任务
task.run();
} catch (RuntimeException x) {
//将运行时异常赋值给thrown,抛出thrown异常
thrown = x; throw x;
} catch (Error x) {
//将错误赋值给thrown,抛出thrown异常
thrown = x; throw x;
} catch (Throwable x) {
//将x赋值给thrown,抛出thrown异常
thrown = x; throw new Error(x);
} finally {
//在用户执行完时,afterExecute做一些后处理操作,比如任务运行出现异常,记录任务执行的异常信息到日志
afterExecute(task, thrown);
}
} finally {
//将task任务置为空
task = null;
//当前工作线程完成的任务加1,不管任务是否正常执行结束
w.completedTasks++;
//释放独占锁
w.unlock();
}
}
//工作线程正常结束
completedAbruptly = false;
} finally {
//处理工作线程退出,看下面对processWorkerExit方法的介绍
processWorkerExit(w, completedAbruptly);
}
}
//从任务队列获取任务,线程的生命周期就是在这里进行维护,比如超过核心线程数的非核心线程在keepAliveTime超时从线程队列中移除等
private Runnable getTask() {
//从同步队列中获取任务是否超时
boolean timedOut = false;
//死循环的获取任务队列中的任务
for (;;) {
//获取ctl的值
int c = ctl.get();
//获取线程池的状态
int rs = runStateOf(c);
//如果线程池的状态大于等于STOP,或者线程池状态等于SHUTDOWN并且队列为空,线程队列的工作线程数减一,直接返回空,线程队列中的工作线程while的获取任务队列中的任务退出
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//线程池中的线程队列线程数减1操作
decrementWorkerCount();
//返回空
return null;
}
//获取线程池中的线程队列中的线程数
int wc = workerCountOf(c);
//allowCoreThreadTimeOut为true,即在任务队列中没有任务时,空闲,核心线程是否退出线程队列,或者线程队列中的工作线程数大于核心线程数,是否超时的从任务队列中获取任务,还是阻塞的从任务队列中获取任务,如果超时,在超时获取不到任务,返回null,工作线程退出线程队列中
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//线程池中的线程队列大于最大线程数或者(timed和timeout都为true),并且线程池中线程队列中的工作线程大于1,或者工作队列为空,
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
//线程池中的线程队列的线程数做减1操作
if (compareAndDecrementWorkerCount(c))
//返回空回去
return null;
//如果线程池中的线程队列的线程数做减1操作失败,重新循环
continue;
}
try {
//如果timed为true超时的从任务队列中获取任务,否则阻塞的从任务队列中获取任务,如果allowCoreThreadTimeOut为false,线程池中的核心线程队列在任务队列中没有任务时,一直阻塞,其他非核心线程会超时的获取任务,在没有获取到任务时,非核心线程会退出线程队列中
Runnable r = timed ?
//超时的从任务队列中获取任务,超时时间keepAliveTime即线程的存活时间,因为在任务队列队列中没有获取到任务时会返回空
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
//阻塞的获取任务队列,核心线程在allowCoreThreadTimeOut为false的时候,阻塞的从同步队列中获取任务,这样可以让核心线程一直在线程队列中
workQueue.take();
//如果从任务队列中获取到任务
if (r != null)
//返回从任务队列中获取到的任务
return r;
//如果从任务队列中超时的获取不到任务,将timeOut超时标志位置为true,下一次循环时线程会退出同步队列中
timedOut = true;
} catch (InterruptedException retry) {
//如果线程阻塞在同步队列中被中断唤醒,设置从同步队列中超时的获取任务的超时标志位timeOut设置位false
timedOut = false;
}
}
}
//线程队列中的线程在处理任务,不管是获取不到任务队列中的任务正常退出,还是由于执行任务队列中的任务编译异常结束,做一些线程退出的处理操作
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//如果线程是异常结束
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
//将线程队列中的线程数减1操作
decrementWorkerCount();
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因为需要将传入进来的工作线程Worker从线程队列Workers中移除,Workers集合不是线程安全的,并且completedTaskCount线程池总共完成的任务数也不是线程安全的
mainLock.lock();
try {
//将线程池已经完成的任务数加上当前工作线程完成的任务数
completedTaskCount += w.completedTasks;
//从线程队列中将结束的任务移除
workers.remove(w);
} finally {
//finally中释放独占锁
mainLock.unlock();
}
//尝试的结束线程,tryTerminate方法可以看上面的介绍
tryTerminate();
//获取ctl值
int c = ctl.get();
//线程池的状态达不到STOP状态
if (runStateLessThan(c, STOP)) {
//并且工作线程是正常结束
if (!completedAbruptly) {
//allowCoreThreadTimeOut如果为true,即核心线程在空闲时也需要被回收,则min等于0,否则等于corePoolSize核心线程数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//如果min等于0,并且任务队列不为空
if (min == 0 && ! workQueue.isEmpty())
//将min赋值为1,确保线程池中至少有个工作线程
min = 1;
//如果线程池中的线程队列已经有大于等于min的工作线程,直接退出,否则的话需要创建线程加入到线程队列中
if (workerCountOf(c) >= min)
//直接退出
return; // replacement not needed
}
//创建非核心工作线程将其非核心工作线程加入到线程队列中,addWorker方法可以看上面的介绍
addWorker(null, false);
}
}
八、线程池任务队列
//获取任务队列
public BlockingQueue<Runnable> getQueue() {
//返回任务队列
return workQueue;
}
//将传入进来的任务从任务队列中移除
public boolean remove(Runnable task) {
//从任务队列中移除任务
boolean removed = workQueue.remove(task);
//尝试的结束线程,tryTerminate方法可以看上面的介绍
tryTerminate();
//返回任务是否从任务队列中移除成功
return removed;
}
//清除任务队列中已取消的任务
public void purge() {
//获取任务队列
final BlockingQueue<Runnable> q = workQueue;
try {
//使用迭代器遍历任务队列
Iterator<Runnable> it = q.iterator();
//迭代器判断是否还有任务
while (it.hasNext()) {
//迭代器获取任务队列中的下一个任务
Runnable r = it.next();
//如果从任务队列中获取到的任务时Future的实例,并且任务已经取消
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
//使用迭代器将任务从任务队列中移除
it.remove();
}
} catch (ConcurrentModificationException fallThrough) {
//因为可能其他线程加入任务到工作队列中,为此使用任务队列将取消的任务移除
for (Object r : q.toArray())
//如果从任务队列中获取到的任务时Future的实例,并且任务已经取消
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
//从任务队列中移除
q.remove(r);
}
//尝试的结束线程,tryTerminate方法可以看上面的介绍
tryTerminate();
}九、线程池线程队列
//获取线程池中的线程队列的线程数
public int getPoolSize() {
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因Workers集合不是线程安全的,为此获取线程队列的线程数需要加锁,否则会有其他线程加入到线程队列中
mainLock.lock();
try {
//如果线程池的状态至少为TIDYING,返回线程队列的线程数0,否则返回线程队列中的线程数
return runStateAtLeast(ctl.get(), TIDYING) ? 0
: workers.size();
} finally {
//在finally中释放独占锁
mainLock.unlock();
}
}
//获取线程池中的线程队列正在工作的线程
public int getActiveCount() {
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因Workers集合不是线程安全的,为此在遍历Worker集合时需要加锁否则会有其他线程加入到线程队列中
mainLock.lock();
try {
//线程队列中正在工作的线程数
int n = 0;
//循环遍历workers的线程队列
for (Worker w : workers)
//如果线程队列中的工作线程正在处理任务,工作线程的状态是锁住的状态,为此判断线程是否锁住来判断工作线程是否正在工作
if (w.isLocked())
++n;
//返回正在工作的线程数
return n;
} finally {
//在finally中释放独占锁
mainLock.unlock();
}
}
//获取线程池中的所有任务数,包括已经执行完成的任务数,正在执行的任务数,否则还未被执行的任务数
public long getTaskCount() {
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因Workers集合不是线程安全的,为此在遍历Worker集合时需要加锁否则会有其他线程加入到线程队列中
mainLock.lock();
try {
//获取线程池中已经完成的任务数
long n = completedTaskCount;
//循环遍历线程队列中的工作线程
for (Worker w : workers) {
//将工作线程已经完成的任务数加入到n中
n += w.completedTasks;
//如果线程队列中的工作线程正在处理任务,工作线程的状态是锁住的状态,为此判断线程是否锁住来判断工作线程是否正在工作
if (w.isLocked())
//将工作线程还未执行完的任务加到n中
++n;
}
//将任务队列中还未执行完成的任务加到n中
return n + workQueue.size();
} finally {
//在finally中释放独占锁
mainLock.unlock();
}
}
public long getCompletedTaskCount() {
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因Workers集合不是线程安全的,为此在遍历Worker集合时需要加锁否则会有其他线程加入到线程队列中
mainLock.lock();
try {
//获取线程池中已经完成的任务
long n = completedTaskCount;
//循环遍历线程队列中的工作线程
for (Worker w : workers)
//将工作线程已经完成的任务数加入到n中
n += w.completedTasks;
return n;
} finally {
//在finally中释放独占锁
mainLock.unlock();
}
}十、终止线程池
//优雅的关闭线程池,对线程池的状态不清楚的看下上面对线程池状态的介绍
public void shutdown() {
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因Workers集合不是线程安全的
mainLock.lock();
try {
//安全校验,是否能关闭线程池
checkShutdownAccess();
//将线程池的状态更改为SHUTDOWN状态
advanceRunState(SHUTDOWN);
//中断所有空闲线程,目的是为了唤醒那些等待任务队列中的线程,然后在一定的时间内获取不到任务退出线程池,interruptIdleWorkers方法看上面介绍
interruptIdleWorkers();
//onShutdown()方法是个模板方法,ScheduledThreadPoolExecutor有对其进行重写
onShutdown();
} finally {
//在finally中释放独占锁
mainLock.unlock();
}
//尝试的结束线程,tryTerminate方法可以看上面的介绍
tryTerminate();
}
//马上关闭线程池,对线程池的状态不清楚的看下上面对线程池状态的介绍
public List<Runnable> shutdownNow() {
//任务队列中所有还未执行的任务
List<Runnable> tasks;
//获取线程池中的独占锁
final ReentrantLock mainLock = this.mainLock;
//加锁,因Workers集合不是线程安全的
mainLock.lock();
try {
//安全校验,是否能关闭线程池
checkShutdownAccess();
//将线程池的状态更改为STOP状态
advanceRunState(STOP);
//中断所有空闲线程,目的是为了唤醒那些等待任务队列中的线程,然后在一定的时间内获取不到任务退出线程池,interruptIdleWorkers方法看上面介绍
interruptWorkers();
//从任务队列中获取所有还未执行的任务
tasks = drainQueue();
} finally {
//在finally中释放独占锁
mainLock.unlock();
}
//尝试的结束线程,tryTerminate方法可以看上面的介绍
tryTerminate();
//返回任务队列中所有还未执行的任务
return tasks;
}
//判断线程池是否已经停止,只要线程池的状态不是RUNNING状态
public boolean isShutdown() {
//判断线程池的是否不是RUNNING状态
return ! isRunning(ctl.get());
}
//判断线程池是否正在结束中
public boolean isTerminating() {
//获取ctl值
int c = ctl.get();
//线程池状态已经不是运行RUNNING状态,并且线程池的状态达不到TERMINATED状态
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
//判断线程池是否已经结束
public boolean isTerminated() {
//线程池的状态至少是TERMINATED
return runStateAtLeast(ctl.get(), TERMINATED);
}
//等待线程池结束,可以超时的等待,也可以一直等待,对条件变量CONDITION不清楚的可以看下我的另一篇AQS的源码分析
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
//将超时参数的单位转换为纳秒
long nanos = unit.toNanos(timeout);
//获取线程池的独占锁,因为条件变量需要拥有独占锁才能使用
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
//如果线程池已经结束,直接返回true,线程池已经关闭
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
//如果超时参数小于等于,直接返回false
if (nanos <= 0)
return false;
//调用Aqs中的ConditionObject类的awaitNanos方法,ConditionObject不清楚的可以看下我的另一篇AQS的源码分析
nanos = termination.awaitNanos(nanos);
}
} finally {
//在finally释放独占锁
mainLock.unlock();
}
}
//循环的更改线程池状态,直到成功,或者线程池已经是这个状态
private void advanceRunState(int targetState) {
//死循环的更改线程池状态
for (;;) {
//获取ctl值
int c = ctl.get();
//如果线程池的状态至少已经是要转换的目标状态,或者使用cas将线程池的状态修改成功,退出循环
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}