目录
一、前言
二、概述
1.优点
2.结构组成
三、原理分析
1.状态实现
2.阻塞队列
3.线程封装
四、源码分析
1.构造函数
2.执行线程入口
3.执行具体过程
线程的重要性便不需要在这里多言。我们开发的时候其实一直在使用线程,只是这个过程被我们忽略了,Tomcat处理每个请求时使用的就是Java的多线程,一个请求即一个线程。
线程的生命周期有五个阶段:
状态转换图:
一个线程的生命周期有如此多的状态变化,如果程序运行很多线程不停地重复着这五个生命周期,对于程序的性能消耗是非常大的,并且如果不控制线程的最大数量,也容易造成内存溢出的危险。而线程池就是为了解决这些个问题而诞生的。
结构图如下:
结构说明:可以很清楚的把这个分为两个部分:
运行时流程图:
流程说明:可以看到其大致流程十分简单,无非是调用线程池的方法后根据方法来决定是否需要再次封装,封装后根据corePoolSize和线程池状态判断继续添加线程是OK的还是线程池出现了异常,如果OK则将其添加进阻塞队列或添加HashSet
此次分析原理使用实例便是Java包concurrent实现的ScheduledThreadPoolExecutor类,这个类继承了ThreadPoolExecutor并自己实现了阻塞延迟队列DelayedWorkQueue。
关于状态的几个参数以及判断方法:
参数说明:截取自ThreadPoolExecutor类的一段代码,分别说明几个参数以及方法的作用。
参数:
方法:
八个参数状态具体的值以及二进制如下图:
个人感想:当时看到这个配置不由得想,为什么COUNT_BITS要取值为29,而不是取值为30或者28,Java线程池有五个状态,如果使用30,高位只能展示4种状态,而使用28,虽然可以展示更多的状态,但3位已经够用了(实际上还多出了3个状态),且取28线程池的容量将会减少一个平方。而五个状态为什么又分别取值为-1、0、1、2和3呢,很好理解,RUNNING取-1,直接判断高三位小于0即可判断,从深层次而言值小的状态都可以转变为值大的状态,而值大的状态无法转变为值小的状态。
ScheduledThreadPoolExecutor类中实现了阻塞队列DelayedWorkQueue,其部分源码如下:
public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService {
static class DelayedWorkQueue extends AbstractQueue
implements BlockingQueue {
private static final int INITIAL_CAPACITY = 16;
private RunnableScheduledFuture>[] queue =
new RunnableScheduledFuture>[INITIAL_CAPACITY];
private final ReentrantLock lock = new ReentrantLock();
private int size = 0;
private Thread leader = null;
private final Condition available = lock.newCondition();
private void grow() {
int oldCapacity = queue.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity < 0)
newCapacity = Integer.MAX_VALUE;
queue = Arrays.copyOf(queue, newCapacity);
}
}
}
集合说明:这个集合是基于堆实现的,默认容量为16,每次扩容都会扩大50%。且使用重入锁ReentrantLock来保证对集合操作是线程安全的。至于堆的实现这里便不做过多赘述。这个集合的作用便是用来存储任务线程,核心线程将一直从这里面获取任务线程来执行,如果一直没有则阻塞轮询,知道有任务线程进来,反反复复。
顺带提一下,ThreadPoolExecutor类中的HashSet
在ScheduledThreadPoolExecutor类中,私有内部类ScheduledFutureTask使用接口RunnableScheduledFuture封装了Runnable接口任务线程,接口源码如下:
public class FutureTask implements RunnableFuture {
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
private Callable callable;
private Object outcome;
private volatile Thread runner;
private volatile WaitNode waiters;
}
该类提供了一个异步可取消的计算类,除了提供Future类的基本方法外,还可以开始或取消计算、查看计算是否完成。一旦计算完成了,则不可以再调用或者计算,除非调用runAndReset方法。
该类也可以用来封装Callable和Runnable对象。
该类共有下列7种状态:
这几种状态的转换关系如下图:
这个类关键是用来搭配内部类DelayedWorkQueue来实现调度给定延迟之后运行某一线程,或者满足某种条件后进行取消或暂停。
关于线程池的源码分析是基于ScheduledThreadPoolExecutor类,其大致源码如下:
public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService {
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), handler);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
}
可以看出,其构造函数共有四种,每个都需要实例化的时候确定corePoolSize,并且最大线程池数量maximumPoolSize都是Integer.MAX_VALUE,即2^32-1,因此使用Java官方的线程池时,需要注意的是不能过多的创建线程数量,因为有些服务器的线程数往往还没达到2^32-1时,程序就已经内存溢出了。
execute和submit方法的部分关键源码如下:
public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService {
public void execute(Runnable command) {
schedule(command, 0, NANOSECONDS);
}
public Future> submit(Runnable task) {
return schedule(task, 0, NANOSECONDS);
}
public Future submit(Runnable task, T result) {
return schedule(Executors.callable(task, result), 0, NANOSECONDS);
}
public Future submit(Callable task) {
return schedule(task, 0, NANOSECONDS);
}
public ScheduledFuture> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture> t = decorateTask(command,
new ScheduledFutureTask(command, null,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
public ScheduledFuture schedule(Callable callable,
long delay,
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture t = decorateTask(callable,
new ScheduledFutureTask(callable,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
protected RunnableScheduledFuture decorateTask(
Callable callable, RunnableScheduledFuture task) {
return task;
}
private void delayedExecute(RunnableScheduledFuture> task) {
if (isShutdown())
reject(task);
else {
super.getQueue().add(task);
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
ensurePrestart();
}
}
}
execute和submit两个方法以及其重载方法是Executor接口和ExecutorService接口分别定义的,其差别无非是有没有返回值,这几个方法最终都会调用到schedule及其重载方法中,接着使用ScheduledFutureTask去封装Runnable线程以及过延迟时间,以实现延迟队列的功能。
从上面的入口可以看到所有最终都会调用到ensurePrestart方法来,因此我们以这个方法源码开始慢慢的深入分析一下Java自己实现的延迟线程池是如何实现的,一些旁支末节或者看方法名称就知道其大致作用的便不做过多分析,部分源码如下:
public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService {
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}
private boolean addWorker(Runnable firstTask, boolean core) {
// 重新调用点
retry:
// 开始外层循环,这层循环是为了持续的监听其它线程是否改变了线程池状态
// 以及数量,并重新获得最新的ctl和状态值
for (;;) {
// 获取ctl的值以及获得线程池当前状态
int c = ctl.get();
int rs = runStateOf(c);
// 判断工作队列是否为空,为空则返回
if (rs >= SHUTDOWN &&
!(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
return false;
// 开始第二层循环,此层循环是为了当前线程在进行CAS操作失败时再次重试
// 同时需要注意的是在此流程中如果core为true,wc= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 使用CAS增加ctl的值,使其+1
if (compareAndIncrementWorkerCount(c))
break retry;
// CAS操作失败
c = ctl.get();
// 如果池运行状态发生变化,则跳至第一层循环重新获取ctl值和状态
if (runStateOf(c) != rs)
continue retry;
}
}
// 线程执行到这里,说明当前线程获得了锁,并且ctl值已经+1
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 这里十分关键,将外部传来的firstTask线程使用内部类Work包装
// 但是当前流程这里的firstTask对象为null
// 需要注意的是Work中的thread线程封装的是它自己
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 加锁对workers当前运行线程集合进行操作
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
// 只有RUNNING或者SHUTDOWN状态并且外部线程firstTask为null
// 才允许调用线程
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
// 将Worker添加进HashSet集合
workers.add(w);
int s = workers.size();
// 最大池数量增加
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
// 释放锁
mainLock.unlock();
}
if (workerAdded) {
// 如果前面的状态判断成功,则运t线程
t.start();
workerStarted = true;
}
}
} finally {
// 如果运行失败,将workers集合的Worker删除,ctl值-1
// 并且尝试终止线程池
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
}
关键的Worker内部类部分关键代码如下:
public class ThreadPoolExecutor extends AbstractExecutorService {
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
// 具体运行的线程,一般指的就是Worker对象
final Thread thread;
Runnable firstTask;
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
// 线程运行后调用到这里
runWorker(this);
}
}
final void runWorker(Worker w) {
// 获得当前线程
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
// 运行此过程线程允许被中断,因为getTask需要和其它线程竞争
w.unlock();
boolean completedAbruptly = true;
try {
// 获得阻塞队列堆顶的线程以便等下执行
// getTask方法也是很重要的,等下再分析
while (task != null || (task = getTask()) != null) {
// 重新加锁
w.lock();
// 当线程池的状态处于:STOP,TIDYING或者TERMINATED并且
// 当前线程是可被中断的,并且wt线程未被中断,则将wt中断
// 这样是为了:
// 当线程池正在暂停,确保线程被中断;如果没有,确保线程未中断
// 这样做的目的是调用shudownNow方法清理中断线程时的再校验
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
// 执行前的操作
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 执行线程的run方法
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// Worker运行完后将workers集合中的对象删除
// 并将濒死的工作线程进行清楚和统计
// 如果线程由于用户任务异常而退出
// 或者运行的工作线程小于corePoolSize
// 或者队列非空但没有工作线程,则可能终止池或替换工作线程。
processWorkerExit(w, completedAbruptly);
}
}
}
可以看到Worker继承了AbstractQueuedSynchronizer类,即自定义锁的同步器,有兴趣可以看一下Java并发编程工具锁深入了解原理实现。
runWorker方法中的getTask方法以及processWorkerExit方法流程源码:
private Runnable getTask() {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 如果线程池状态失效或者阻塞队列为空,则直接返回,并且数量减一
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果需要根据时间判断,则调用poll方法,否则直接拿取头节点
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
// 获取超时
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 如果runWorker方法异常结束,则直接将数量-1
if (completedAbruptly)
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 去除workder集合中的对象
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试终止线程池
tryTerminate();
int c = ctl.get();
// 如果处于SHUTDOWN或者RUNNING状态下
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 判断是否有额外的线程需要处理,
if (workerCountOf(c) >= min)
return;
}
// 处理非核心线程
addWorker(null, false);
}
}
因此其逻辑核心便是确保核心线程和阻塞队列要被全部用完才会去创建非核心线程: