ThreadPoolExecutor类概述
构造函数
ThreadPoolExecutor类提供了四个构造函数,但前三个都间接调用了第四个构造函数。
//间接调用最后一个构造函数,采用默认的拒绝策略AbortPolicy和默认的线程工厂
ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue<Runnable>)
//间接调用最后一个构造函数,采用默认的默认的线程工厂
ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue<Runnable>,
RejectedExecutionHandler)
//间接调用最后一个构造函数,采用默认的拒绝策略AbortPolicy
ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue<Runnable>, ThreadFactory)
//前面三个分别调用了最后一个
ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue<Runnable>, ThreadFactory, RejectedExecutionHandler)
//最后一个构造函数的具体实现
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
//参数合法性检验,核心线程数目、最大线程数目、线程空闲回收时间不得小于0,最大线程池不得小于核心线程数数目
if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)
throw new IllegalArgumentException();
//参数合法性检验,阻塞队列,线程工厂,决绝策略不得为空
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;//核心线程数大小
this.maximumPoolSize = maximumPoolSize;//最大线程数目
this.workQueue = workQueue;//阻塞队列
this.keepAliveTime = unit.toNanos(keepAliveTime);//空闲回收时间
this.threadFactory = threadFactory;//线程工厂
this.handler = handler;//拒绝策略
}
上述代码中,参数详细说明:
corePoolSize:(volatile int)类型,表示线程池核心池的大小。
maximumPoolSize:(volatile int)类型,表示线程池最多创建的线程数目。
注:Java线程池分两部分,一块是核心池,一块是临时池,当核心池的线程满了且阻塞队列中任务满了,再有任务提交执行时,则创建"临时线程",可创建的临时线程的数目为maximumPoolSize-corePoolSize。当线程总数等于maximumPoolSize且阻塞队列满了,再有任务提交时,采取拒绝策略。
workQueue:阻塞队列。常用的有ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、DelayQueue。
keepAliveTime:线程空闲回收时间。
threadFactory:生成线程的工厂类。默认为:Executors.defaultThreadFactory();
handle:拒绝策略。默认为defaultHandler = new AbortPolicy();
注:常用拒绝策略有以下几种:
- ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
- ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
- ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
核心字段
/*AtomicInteger类型,用来标识线程池的状态,以及线程池里面线程的数量,
初始值为1110 0000 0000 0000 0000 0000 0000 0000 前三位是线程池的状态,其中:
000 SHUTDOWN 不接受新任务但是处理阻塞队列中的任务
010 TIDYING 所有任务都被终止,工作线程为0
001 STOP 不接受新任务也不处理阻塞队列中的任务并且中断所有线程池中正在运行的任务
011 TERMINATED 不接受新任务也不处理阻塞队列中的任务并且中断所有线程池中正在运行的任务
111 RUNNING 接受新的任务并处理阻塞队列中的任务
注:关于阻塞队列,后续会说,暂且理解为一个存放还未执行线程的队列就好。
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
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;
//在某些情况下用来存储任务,并将任务提供给线程池中的工作线程
private final BlockingQueue<Runnable> workQueue;
//用来对pooSize、corePoolSize、maximumPoolSize、runState、workers修改时候同步
private final ReentrantLock mainLock = new ReentrantLock();
//线程池中所有线程的集合,访问和修改需要mainLock的配合
private final HashSet<Worker> workers = new HashSet<Worker>();
//用来支持waitTemination
private final Condition termination = mainLock.newCondition();
//跟踪线程池中线程的最大值,具体的猜测是为了矫正poolsize,访问和修改需要配合mainLock
private int largestPoolSize;
//已完成任务的数量,在任务处于Terminate状态时才更新,访问和修改需要mainLock的配合
private long completedTaskCount;
/*
* 一下参数都是用户控制的,全部被声明为了Volatile类型的值,这样能够确保在多线程下,每个
* 线程都能够获取到最新值。
*/
//线程工厂,用户可以自定义,以便在想线程池创建线程时附加一些个人操作
private volatile ThreadFactory threadFactory;
//当线程池处于shutdown或者处于饱和时执行的拒绝策略
private volatile RejectedExecutionHandler handler;
//设置线程池中空闲线程等待多时毫秒被回收
private volatile long keepAliveTime;
//指定线程池中的空闲线程是否一段时间被回收,false一直存活
private volatile boolean allowCoreThreadTimeOut;
//核心线程池大小,若allowCoreThreadTimeOut被设置,全部空闲超时被回收的情况下会为0
private volatile int corePoolSize;
//最大线程池大小,不得超过CAPACITY
private volatile int maximumPoolSize;
此代码,将线程状态和线程数放在了一个int值里面,高三位代表线程状态,低29位表示线程数目。
其中clt(AtomicInteger)可以理解为线程安全的整数。关于clt常用的几个操作,即对线程状态和线程数的操作:
runStateOf(int c)
是通过与的方式,在clt字段中获取到clt的前三位,也就是线程池的状态标识。
workerCountOf(int c)
是通过与的方式,在clt字段中获取到clt的后29位,也就是线程池中的线程数量。
ctlOf(int rs, int wc)
是通过或的方式,将修改后的线程池状态rs和线程池中线程数量打包成clt。
isRunning(int c)
SHUTDOWN的状态是0左移29为得到的,比他大的均是线程池停止或销毁状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
private static boolean isRunning(int c) {return c < SHUTDOWN;}
核心方法
线程池初始化之后,可以通过调用submit和execute方法来执行任务。
public Future<?> submit(Runnable task)
public <T> Future<T> submit(Runnable task, T result)
public <T> Future<T> submit(Callable<T> task)
三个构造函数均是返回一个Future,关于Future内容还有很多,暂时我们只需要理解,我们通过Future可以获取到提交线程的执行结果和抛出的异常,可以监视线程的运行,以public Future<?> submit(Runnable task) 为例简单介绍一下:
//sumit函数是在ThreadPoolExecute的父类AbstractExecutorService实现的,最终还是调用的子类的execute方法
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
其实submit内部也是调用execute方法,下篇文章将详细讲解execute方法的执行逻辑。