线程池系列:
在文章开始之前,我们先要明白为啥要有线程池这么个东西。线程是一种稀缺资源,若不加以限制,不仅会占用大量资源,还会影响系统的稳定性。而线程池可以对线程的创建与停止、线程数量等等因素加以控制,使得线程在一种可控的范围内运行,在保证系统稳定运行的同时,还使得性能调优更加方便。另外,每次请求到来时,由于线程的创建已经完成,所以可以直接执行任务,减少了每次创建线程、销毁线程的开销,提高了响应速度。
OK,下面我们就进入正戏,源码…
ThreadPoolExecutor 核心继承关系,成员变量及主要构造函数:
public class ThreadPoolExecutor extends AbstractExecutorService {
// ctl 线程池状态控制字段,由两部分组成:
// int ctlOf(int rs, int wc) { return rs | wc; }
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 1:workerCount wc 工作线程数,我们限制 workerCount 最大到(2^29)-1,大概 5 亿个线程
private static final int COUNT_BITS = Integer.SIZE - 3;// 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1;// =(2^29)-1=536870911
// 2:runState rs 线程池的状态,提供了生命周期的控制,源码中有很多关于状态的校验,状态枚举如下:
private static final int RUNNING = -1 << COUNT_BITS;//536870912
private static final int SHUTDOWN = 0 << COUNT_BITS;//0
private static final int STOP = 1 << COUNT_BITS;//536870912
private static final int TIDYING = 2 << COUNT_BITS;//1073741824
private static final int TERMINATED = 3 << COUNT_BITS;//1610612736
// Worker 线程池中任务执行的最小单元
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{...}
// 任务队列,阻塞队列,来保持线程的存活周期
// 注:这里使用阻塞队列而不是普通容器,是为了worker在取任务时借助它的线程调度能力
// 比如当线程池中的线程空闲下来了,它就会在队列的另一端等待外部线程投递任务
// 这里注意,因为将外部线程的任务放入任务队列调用的是offer方法,所以入队时不会出现外部线程阻塞
private final BlockingQueue<Runnable> workQueue;
// 工作线程集合,包含线程池中所有的工作线程
private final HashSet<Worker> workers = new HashSet<Worker>();
// 锁,大多数情况下是控制对 workers 的访问权限(如将新worker加入)
private final ReentrantLock mainLock = new ReentrantLock();
private final Condition termination = mainLock.newCondition();
// 已完成任务的计数
volatile long completedTasks;
// 线程池最大容量
private int largestPoolSize;
// 已经完成的任务数
private long completedTaskCount;
//-----------------------------用户可控属性(volatile)-----------------------------
// 可以使用 threadFactory 创建 thread
// 创建失败一般不抛出异常,只有在 OutOfMemoryError 时候才会
private volatile ThreadFactory threadFactory;
// 线程空闲的最大时间
private volatile long keepAliveTime;
// coreSize,allowCoreThreadTimeOut决定是否回收
private volatile int corePoolSize;
// maxSize,除核心线程外,空闲就会回收
private volatile int maximumPoolSize;
// 饱和或者运行中拒绝任务的 handler 处理类
private volatile RejectedExecutionHandler handler;
// 默认的拒绝策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
// 设置 true 的话,核心线程空闲 keepAliveTime 时间后,也会被回收
// 需要调用allowCoreThreadTimeOut方法进行设置,默认false
private volatile boolean allowCoreThreadTimeOut;
//-------------------------------构造函数----------------------------------------
// 构造函数的作用就是设置上面的volatile变量们
// 注:前五参数个必有,theadFactory与rejected可以没有
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {...}
}
这里把几个相关参数再说一下:
线程池状态
- RUNNING:可以接收新任务,同时也可以处理阻塞队列里面的任务
- SHUTDOWN:不可以接收新任务,但可以处理阻塞队列里面的任务
- STOP:不可以接收新任务,也不处理阻塞队列里的任务,同时中断正处理的任务
- TIDYING:属于过渡阶段,在这个状态表示所有任务已经结束,当前线程池无有效线程,并将调用terminal方法
- TERMINALED:终止状态
拒绝策略
- AbortPolicy(默认):抛出异常
- CallerRunsPolicy:不使用线程池,主线程来执行
- DiscardPolicy:直接丢弃任务
- DiscardOldestPolicy:丢弃队列中最老任务