概念
线程池就是一个维护一个线程集合的类,因为线程的创建代价很大,为了提高效率,所以就出现了线程池,由线程池负责线程的创建和销毁,用户只需提交任务给线程池执行即可
如何使用
- 创建线程池
直接看完全构造函数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数说明:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:线程空闲时间
- unit:线程空闲时间单位
- workQueue:任务队列
- threadFactory:线程工厂类,用来创建线程
- handler:线程给拒绝时执行的方法
以上参数的详细说明后面原理会有解释
创建完后,提交任务进行执行
可以通过以下方法进行任务提交
1. execute:向线程池提交一个Runnable任务进行执行
2. submit:向线程池提交一个Runnable任务进行执行,和execute的区别是,会返回一个Future,Future可以用来获取任务的执行结果
原理分析
execute方法分析
分析execute方法,看看线程池的线程是如何创建,如何运行,以及线程是如何维护的
首先看一张图,理解整个过程
简单说明:用户向线程池类提交任务进行执行,线程池类会判断运行线程池是否需要创建新的线程去处理,如果需要创建,则直接在运行线程池中创建线程然后执行任务,如果不需要创建新的线程,则放入任务队列,由运行线程池中已经存在的线程从队列获取任务来执行
上图我们看到主要几个对象:运行线程池,worker和任务队列
任务队列就是构造函数中的workQueue
worker是线程池中运行任务的对象,通过thread.start,调用worker的run方法,来运行提交到线程池中的任务,worker的数量就是运行线程池中的线程的数量
运行线程池就是正在运行的线程的集合,这个集合的大小和参数corePoolSize
和maximumPoolSize
有关,集合最大不超过maximumPoolSize
,常态运行时一般为corePoolSize
接下来就看这个运行线程池的执行过程
我把运行线程池中的线程数量称为运行线程数
当用户调用execute方法
- 如果运行线程数小于
corePoolSize
,则在运行线程池中增加一个worker,同时运行该worker - 如果运行线程数大于
corePoolSize
,则向运行队列workQueue
中添加任务 - 当运行队列已满
workQueue
,- 如果运行线程数小于
maximumPoolSize
,则继续往运行线程池中添加worker - 如果运行线程数大于
maximumPoolSize
,则调用handler
拒绝任务
- 如果运行线程数小于
以上逻辑对应源码:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//ctl是一个复合参数,保存了线程池的状态和运行线程数,workerCountOf可以获取出运行线程数
if (workerCountOf(c) < corePoolSize) {//如果运行线程数小于corePoolSize
if (addWorker(command, true))
//添加线程,addWorker第二个参数true调试添加的是核心线程
return;
c = ctl.get();
}
//workQueue.offer,向运行队列中放入任务
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}else if (!addWorker(command, false))//运行队列添加任务失败后,向运行线程池中加worker,addWorker中有关于maximumPoolSize的逻辑处理,如果添加失败,则调用reject方法拒绝任务
//
reject(command);
}
addWorker,部分代码有省略
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
for (;;) {
int wc = workerCountOf(c);
//判断运行线程数是否超过范围
//核心线程则不能超过corePoolSize,
//非核心线程不能超过maximumPoolSize
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//运行线程数+1
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
//runStateOf获取线程池状态
if (runStateOf(c) != rs)
continue retry;
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
final ReentrantLock mainLock = this.mainLock;
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
mainLock.lock();
try {
//向运行线程池添加worker
workers.add(w);
workerAdded = true;
} finally {
mainLock.unlock();
}
if (workerAdded) {
//运行worker
//关于worker对象,它其实是一个Runnable的实现类,所以可以用线程运行
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
接下来再看worker是如何执行任务的
上图可以看到从woker到队列有个箭头,意思是worker会从队列中获取任务执行
看源码如何处理
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//当前woker的第一个任务,这个就是用户通过execute提交的任务
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//getTask方法可以从任务队列中获取下一个任务,如果没有获取到,此处会阻塞,这里涉及到了参数workQueue,keepAliveTime
while (task != null || (task = getTask()) != null) {
w.lock();
try {
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 {
//循环执行完后,则当前work的生命也即将结束,运行线程池的数量会-1
processWorkerExit(w, completedAbruptly);
}
}
getTask方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
retry:
for (;;) {
int c = ctl.get();
boolean timed; // Are workers subject to culling?
for (;;) {
int wc = workerCountOf(c);
//判断线程是否需要空闲超时,如果设置了allowCoreThreadTimeOut,那么只要线程空闲超时,那么该线程便不再在任务队列这里等待,直接往下执行完毕,退出,此时worker就执行完了,运行线程数会-1,否则只有会减少大于corePoolSize的线程
timed = allowCoreThreadTimeOut || wc > corePoolSize;
if (wc <= maximumPoolSize && ! (timedOut && timed))
break;
if (compareAndDecrementWorkerCount(c))
return null;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
try {
//从运行队列中获取任务,poll,设置超时时间keepAliveTime,超过这个时间没有获取到,就会返回空,take无限等待,知道获取到任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
shutdown方法分析
线程池什么时候会停止呢,如果我们向线程池提交了一个任务,执行完毕后,线程池是否就会自动停止?
来看woker的runWorker方法,执行完后执行processWorkerExit
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
try {
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 {
//woker执行完后执行该方法
processWorkerExit(w, completedAbruptly);
}
}
processWorkerExit
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
//将当前worker从运行线程池中移除
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
//计算最小线程数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//此处执行的就保证了线程池中至少有一个worker在运行
addWorker(null, false);
}
}
可以看到上面代码最后有一个addWorker,所以当线程池中所有任务运行完后,线程池中仍然会至少有一个worker在运行
如何停止线程池?
方法shutdown,shutdownNow
- shutdown
停止线程池,在shutdown执行前提交的任务都会继续执行,shutdown执行后,无法继续提交新的任务了,在线程池中所有任务运行完后,线程池就会停止
注意执行shutdown并不会马上停止线程池,只有当线程池中的任务都运行完毕,才会停止,在实际编程中可以这么做
executor.shutdown();
while(true){
try {
if(executor.awaitTermination(1,TimeUnit.SECONDS)){
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
shutdown源码
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
//设置状态为SHTUDOWN
advanceRunState(SHUTDOWN);
//中断正在等待任务队列的worker
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
- shutdownNow
停止线程池,它会将任务队列中没有执行的任务取出来作为返回数据,取出来的任务数据会从任务队列中删除,会中断所有线程,注意,如果运行中的任务没有处理中断,那么任务仍然会运行完
源码:
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
//设置状态为STOP
advanceRunState(STOP);
//中断所有的worker,包括正在运行中的任务
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}