本篇文章主要讲述自己对于线程池的理解。
创建线程池,能够降低线程小韩,比如通过线程池不需要频繁的创建线程,销毁线程。
能够对线程进行统一管理和监控,防止出现不断创建线程的资源卡死等问题。
线程池的参数:
线程池有各种各样的参数:线程池大小,线程池扩容最大大小,线程是的空闲时间,线程的阻塞队列类型,任务太多了的处理策略。
线程池大小:线程池的大小,当可执行任务达到后,只要线程的数量还没有到达这个数量,那么无论是否有空闲线程,就会常见一个新的线程来执行任务。
扩容最大大小:当线程池满了,我们的队列也满了,那么就必须创建一个新的扩容线程来处理任务。
空闲时间:为扩容的线程来服务的,设定一个时间,让扩容的线程执行完任务后,并不马上销毁而是等一下看有没有新任务。没有则销毁。
时间单位:空闲时间的单位,天,小时等。
队列:当线程池的处理能力不行的时候,先把任务存储到队列里。
策略:当线程池,队列,扩容线程也满了的情况下,根据自己的策略来处理到来的任务。
对应于线程池的参数有了几种不同的队列:
1、固定线程池 FixedThreadPool 。准确的来说,这个意思就是不能够扩容的线程池,也就是说最大扩容线程参数是无效的。那么针对于keepAlive空闲时间参数也是无效的喽。队列采用无限 LinkedBlockingQueue。一般用于重负载的场景。
2、单线程 SingleThreadPool 和单个线程执行任务差不多,只不过有队列,能够存储任务。可以根据任务的存储来慢慢的处理任务。任务与任务之间不会冲突。
3、多线程池 CachedThreadPool 单个的,固定的都有了,这会来个无限的。既然是无限的,那么就会遇到一个任务就创建一个线程来处理。
execute方法论述
public void execute(Runnable command) {
//校验任务不为空
if (command == null)
throw new NullPointerException();
//获取 c 线程池的运行状态
int c = ctl.get();
//根据这个状态很有意思,高三位为记录线程池的运行状态,剩下的是记载线程的数目
if (workerCountOf(c) < corePoolSize) {
//addWorker 未到达核心线程数,创建新的线程,执行任务,当遇到不是RUNNING状态的时候,会return false
if (addWorker(command, true))
return;
c = ctl.get();
}
//线程池是运行状态,并且可以添加任务到阻塞队列,
if (isRunning(c) && workQueue.offer(command)) {
//添加完毕之后,再次对线程池的状态进行检测
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
//==0 表示处于可以接受任务状态
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//创建新任务失败,则调用拒绝策略方法 reject
else if (!addWorker(command, false))
reject(command);
}
addWorker方法 的上部分,先确保可以创建新线程,执行任务。
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 如果不满足线程池接受任务的状态,则返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//如果线程数量大于最大容量,那么不好意思,返回false.不会循环
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//cas 操作,成功 退出for循环
if (compareAndIncrementWorkerCount(c))
break retry;
//再次获取运行状态,如果状态仍旧和rs是一个返回值,那么证明cas操作失败。continue 重试
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
addWorker方法,开始创建线程执行任务
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//把线程任务包装为Worker节点,Worker继承了AQS
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
//全局同步锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
//仍旧判断 线程池的状态是否为 可工作状态(RUNNING SHUTDOWN)
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) {
t.start();
//同时更新线程启动的状态
workerStarted = true;
}
}
} finally {
//线程未启动,则表示t.start可能失败了,所以进入添加新任务失败方法
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
当在addWorker方法里,会执行t.start方法,启动线程。其实在这里已经不是我们execute传入的那个线程了。看Worder类是怎么包装我们传入的线程的。
Worker(Runnable firstTask) {
//Worker构造函数里,先表明为运行完毕才可以中断
setState(-1);
//这个firstTask是我们要运行的任务
this.firstTask = firstTask;
//这里通过线程工厂,返回线程对象,注意这里传递的是this对象。而不是我们传入的task了
//也就是说,当调用线程的start方法时,进入run,不是调用task的run,而是Worker的run方法。
this.thread = getThreadFactory().newThread(this);
}
再往下走,进入run方法后,run方法调用了runWorker方法。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//获取任务对象
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//任务不为空,或者能够从workQueue里获取到任务的时候
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
//可以通过继承ThreadPoolExecutor来改写beforeExecute 有点类似静态代理的味道
beforeExecute(wt, task);
Throwable thrown = null;
//这里真正开始执行我们的任务了
try {
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 {
processWorkerExit(w, completedAbruptly);
}
}
getTask方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//如果减工作线程数量失败,则重试
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//设置keepAliveTime 超时时间未获取到任务。则
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
//如果获取到任务的话,则返回任务。否则timeOut为true。在下一次循环之后,会return null
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}