介绍:
线程池主要解决两个问题:一是当执行大量异步任务时线程池能够提供较好的性能在不使用线程池时,每当需要执行异步任务时直接 new 个线程来运行,而线程的创建和销毁是 要开销的 线程池里面的线程是可复用的 ,不需要每次执行异步任务时都重新创建和销毁线程。二是线程 也提供了 种资源限制和管理的手段,比如可以限制线程的个数,动态新增线程等 每个ThreadPoo!Executor也保留了一些基本的统计数据, 比如当前线程池完成的任务数目等。
ThreadPoolExecutor 的实现实际是一个生产消费模型, 当用户添加任务到线程池时相当于生产者生产元素, workers 线程工作集中的线程直接执行任务或者从任务队列里面获取任务时则相当于消费者消费元素。
成员变量ctl:
成员变量ctl是一个 Integer 的原子变量 ,用 来记录线程池状态和线程池中线程个数,类似于 ReentrantReadWri teLock 使用 一个变量来保存两种信息。
这里假设 nteger 类型是 32 位二进制表示,则其中高 位用来表示线程池状态,后面
29 位用来记录线程池线程个数。
//(高3 位)用来表示线程池状态, (低29位)用来表示线程个数
//默认是RUNNING状态,线程个数为0
private final Atomicinteger ctl =new Atomicinteger(ctlOf(RUNNING, 0)) ;
//线程个数掩码位数,并不是所有平台 工的类型都是32 的,所以准确地说, 是具体平台 Integer 进制
位数- 后的剩余位数所表示的数才是线程的个数
private static final int COUNT BITS = teger.SIZE - 3 ;
//线程最大个数(低29位) 00011111111111111111111111111111
private static final int CAPACITY (1 < COUNT BITS) - 1 ;
线程池状态
//(高 3位) : 11100000000000000000000000000000
private static final 口 t RUNNING = -1 < COUNT BITS;
// ( 千主) : 00000000000000000000000000000000
private static final 工口 SHUTDOWN = 0 < COUNT_BITS ;
//(高 3位) : 00100000000000000000000000000000
private static final int STOP = 1 < COUNT BITS ;
//( 高 3位) : 01000000000000000000000000000000
private static final int TIDYING = 2 < COUNT BITS;
//( 高 3位) : 01100000000000000000000000000000
private static nal int TERMINATED = 3 < COUNT_BITS;
//获取高 3位(运行状态)
private static int runStateOf(int c) { return c &~CAPACITY ; )
//获取低29位(线程个数)
pr vate static 工口 workerCountOf(int c) { return c & CAPACITY ; )
//计算ctl 新值(线斗呈状态与线程个数
private static int ctlOf (int rs, int we) { return rs I we; )
线程池状态:
• RUNNING :接受新任务并且处理阻塞队列里的任务
• SHUTDOWN :拒绝新任务但是处理阻 队列里的任务
• STOP :拒绝新任务并且 弃阻塞队列 的任务 ,同时会中断正在处理的任务。
• TIDYING: 所有任务都执行完(包含阻 队列里面的任务)后当前线程池活动线程
数为0, 将要调用 terminated 方法
• TERMINATED: 终止状态。 terminated 方法调用完成 以后的状态
线程池状态转换列举如下:
• RUNNING -> SHUTDOWN 显式调用 hutdown () 方法 或者隐式调用了 finalize()
方法里面的 shutdown() 方法。
• RUNNING SHUTDOWN)-》 STOP 显式调用 shutdownNow() 方法。
• SHUTDOWN -》TIDYING 当线程池和任务队列都为空时。
• STOP -》TIDYING 当线程池为空时。
• TIDYING–》TERMIATED : terminated() hook 方法执行完成。
线程池参数
- corePoolSize :线程池核心线程个数。
- workQueu :用于保存等待执行的任务的阻塞队列,比如基于数组的有界
ArrayBlock ingQueue 、基于链表的无界 LinkedBlockingQueu 、最多只有一个元素的
同步队列 SynchronousQueue 及优先级队列 PriorityBlockingQueu 等。 - maximunPoolSize : 线程池最大线程数量。
- ThreadFactory :创建线程的工厂。
- RejectedExecutionHandler :饱和策略,当 队列满并且线程个数达maximunPoolSize
后采取得策略, 比如 AbortPolicy (抛出异常〉、 CallerRunsPolicy (使用调用者所在
线程来运行任务) DiscardOldestPolicy (调用 poll 丢弃一个任务,执行当前任务)
DiscardPolicy (默默丢弃,不抛出异常) - keeyAliveTime :存活时间 如果当前线程池中的线程数量比核心线程数量多 ,并且是
闲置状态, 则这些闲置的线程能存活的最大时间。 - TimeUnit : 存活时间的时间单位。
源码分析
public void execute(Runnable command) {
//(1 )如果任务为 null ,则抛出 NPE异常
if (command == null)
throw new NullPointerException();
//(2 )获取当前线程池的状态+线程个数变量得组合值
int c = ctl.get();
//(3 )当前线程池中线程个数是否 小于corePoolSize ,小于则开启新线程运行
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//( 4)如果线程池处于RUNNING状态,则添加任务到阻塞队列
if (isRunning(c) && workQueue.offer(command)) {
// (4.1) 二次检查
int recheck = ctl.get();
// (4.2)如果当前线程;也状态不是RUNNING状态从队列中删除任务,并执行拒绝策略
if (! isRunning(recheck) && remove(command))
reject(command);
// (4.3)否则如果当前线程池为空 则添加 个线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//(5) 如果队列满,则 新增线程 ,新增失败则执行拒绝策略
else if (!addWorker(command, false))
reject(command);
}
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// (6) 检查队列是否只在必妥时为空
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
// (7) 循环CAS增加线程个数
for (;;) {
int wc = workerCountOf(c);
// (7.1) 如果线程个数超限则返回 false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// (7.2) CAS增加线程个数 ,同时只有一个线程成功
if (compareAndIncrementWorkerCount(c))
break retry;
// (7.3) CAS 失败了,则看线程池状态是否变化了,变化则跳到 层循环重新尝试获取线程池状态,否则内层循环重新CAS
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
}
}
// (8)到这里说明 CAS成功了
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// (8.1) 创建worker
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
// (8.2)加独 ,为了实现workers 同步,因为可能多个线程调用了线程池 execute
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 添加任务
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// (8.3)添加成功后则启动任务
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
线程池巧妙地使用一个 Integer 类型的原子变量来记录线程池状态和线程池中 线程个
数。通过线程池状态来控制任务的执行,每个 worker线程可以理多个任务。线程池
线程 得复用减 少了线程创建和销毁的开销。