一、ThreadPoolExecutor线程池执行流程流程
线程池的作用:降低资源消耗、调高相应速度、提高线程的可管理行
来源引自:https://blog.csdn.net/fuyuwei2015/article/details/72758179
本图是概况图
本图是明细图
1.1 对RejectedExecutionHandler(拒绝策略)接口的解释:在使用线程池并使用有界队列时,如果队列满了,
任务添加到线程池就会有问题,为此提供了拒绝策略。策略有以下几种:
(1)、AbortPolicy:线程池默认的策略,如果任务添加到线程池失败,
会抛出RejectedExecutionException异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//不做任何处理,直接抛出异常
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " +e.toString());
}
(2)、DiscardPolicy:如果添加任务失败,则放弃,不会抛出任何异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//就是一个空的方法
}
(3)、DiscardOldesPolicy:如果任务添加到线程池失败,会将队列中最早添加的任务移除;
并再次尝试添加,如果添加失败则会继续按照该策略执行
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//移除队头元素
e.getQueue().poll();
//再尝试入队
e.execute(r);
}
}
(4)、CallerRunsPolicy:如果任务添加失败,主线程会自己调用执行器中的execute方法来执行该任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//直接执行run方法
r.run();
}
}
(5)、用户自定义策略:如果以上几种策略都不合适,将根据场景自定义拒绝策略,必须实现
RejectedExecutionHandler接口,并将自定义的逻辑写在rejectedExecution()方法中。
public class MyRejectPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//Sender是我的Runnable类,里面有message字段
if (r instanceof Sender) {
Sender sender = (Sender) r;
//直接打印
System.out.println(sender.getMessage());
}
}
}
1.2 明细流程图步骤讲解:
1.如果当前运行的线程少于corePoolSize(核心线程数),
则创建新线程来执行任务(注意:执行这一步要获取全局锁)。
2.如果运营的线程等于或多余corePoolSize(核心线程数),
则将任务加入到BlockingQueue(阻塞队列)。
3.如果无法将任务加入BlockingQueue(阻塞队列),
则在非corePool中创建新的线程处理任务(注意:执行这一步要获取全局锁)。
4.如果创建新线程将使当前运行线程超出maximumPoolSize(线程池最大数量)、任务将被拒绝,
并调用RejectedExecutionHandler.rejectedExecution()方法。
备注:ThreadPoolExecutor采取上述整体设计思路,是为了在执行execute()方法时,
尽可能避免获取全局锁(获取全局锁是一个严重的可伸缩瓶颈),
当运行的线程数大于等于corePoolSize(核心线程数)都会执行步骤2,因为步骤2不用获取全解锁。
二、ThreadPoolExecutor创建线程池时的参数及方法作用
1.参数描述:
corePoolSize:核心线程池基本大小,活动线程小于corePoolSize则直接创建,
大于等于则添加到workQueue(工作队列)中,队列满了才创建新的线程,
当提交一个任务到线程池时,线程池会创建一个线程来 执行任务,
即使其他空闲的基本线程能够执行新任务也会创建线程,
等到需要执行的任务数大于线程池基本大小时就不在创建、
如果调用了线程池的prestartAllCoreThreads()方法,线程池会
提前创建并启动所有基本线程。
maximumPoolSize:最大线程数,超过就reject(拒绝);线程池允许创建最大线程数。
如果队列满了,并且已创 建的线程数小于最大线程数,
则线程池会在创建新的线程执行任务。
keepAliveTime:线程池的工作线程空闲后保持存活的时间,
如果任务很多并且每个任务执行时间比较短,可以调大时间,提高线程利用率。
unit:线程活动保持时间的单位,有天(DAYS)、小时(HOURS)、分钟(MINUTES)、
毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和
纳秒(NANOSECONDS,千分之一微秒)
workQueue:工作队列,线程池中的工作线程都是从工作队列中获取任务进行执行的。
工作队列类型包括:
ArrayBlockingQueue:有界队列,FIFO,需指定队列大小,如果队列满了,
会触发线程池的RejectedExecutionHandler逻辑
LinkedBlockingQueue:无界队列,FIFO,可以无限向队列添加任务,直到内存溢出
SynchronousQueue:阻塞队列,每个put必须等待一个take,同步队列的容量只有1个队列,
其中Executors.newCachedThreadPool使用的就是该队列
PriorityBlockingQueue:优先级队列,线程池会优先选取级别高的任务执行,
队列中的元素必须实现Comparable接口
threadFactory:新建工厂,使用new CustomThreadFactory定制线程工厂
RejectedExecutionHandler(拒绝策略):当提交任务数超过
maximumPoolSize(线程最大数)+workQueue(工作 队列)之和时,
任务会交给 RejectedExecutionHandler(拒绝策略)来处理
2.方法描述:
execute():向线程池提交任务,该方法没有返回值,不会返回执行结果,
该方法需要传入Runnable类的实例。
threadsPool.execute(new Runnable() {
@Override
public void run() {
}
});
submit():向线程池提交任务,会返回future对象,通过future对象判断任务是否执行成功,
并通过uture对象的get()方法获取返回值。其中get()方法会阻塞当前线程直到任务完成,
而get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,
这时有可能任务没有执行完。
Future
shutdown:关闭线程池,将线程池变成shutdownNow状态,
此时不能再往线程池中添加新任务,否则会抛出RejectedExecutionException异常,
此时线程池不会立刻退出,直到添加到线程池中的任务都已处理完成,才会退出。
shutdownNow:关闭线程池并中断任务,将线程池立刻变成stop状态,
此时不能再往线程池添加新任务, 终止等待执行的线程,
并返回它们的列表。该方法并不能保证线程池就一定会立即退出。
三、ThreadPoolExecutor类的结构
ThreadPoolExecutor继承AbstractExecutorService(抽象类),
其中AbstractExecutorService(抽象类)实现ExecutorService接口,
其中ExecutorService接口继承Executor接口
1.Executor接口中的方法有
public interface Executor {
void execute(Runnable command);//向线程池提交任务
}
2.ExecutorService接口中的方法有
public interface ExecutorService extends Executor {
//关闭Executor,不再接受提交任务
void shutdown();
//关闭Executor,不再接受提交任务,并且不再执行入队列中的任务
List shutdownNow();
//通过ctl属性判断当前的状态是否不是RUNNING状态
boolean isShutdown();
//通过ctl属性判断当前的状态是否为TERMINATED状态
boolean isTerminated();
//阻塞等待shutdown请求后所有线程终止,会有时间参数,超时和中断也会令方法调用结束
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
Future submit(Callable task);
Future submit(Runnable task, T result);
Future> submit(Runnable task);
List> invokeAll(Collection extends Callable> tasks)
throws InterruptedException;
List> invokeAll(Collection extends Callable> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
T invokeAny(Collection extends Callable> tasks)
throws InterruptedException, ExecutionException;
T invokeAny(Collection extends Callable> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
3.AbstractExecutorService(抽象类)是ExecutorService(接口)的一个抽象实现,
之所以抽象是因为和执行器本身声明周期相关的方法在此类中并未实现,需要子类扩展完善。
四、源码分析
按照程序运行顺序分析
1.创建线程池(构建全参数构造方法) 创建线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0){
throw new IllegalArgumentException();
}
if (workQueue == null || threadFactory == null || handler == null){
throw new NullPointerException();
}
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
2.execute() 方法 (用于提交任务)
public void execute(Runnable command) {
// 提交执行的任务,不能为空
if (command == null){
throw new NullPointerException();
}
int c = ctl.get(); //获取当前有效的线程数和线程池状态
//1.判断当前正在运行的线程数是否小于核心线程数; 是:新创建一个线程执行任务;否:将任务放到队列中
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true)){ //在addWorker中创建工作线程执行任务
return; //成功并返回
}
//失败:失败原因可能是:线程池已经shutdown,shutdown的线程池不再接收新任务
c = ctl.get(); //取得AtomicInteger里存储的数值
}
//2.当前核心线程池中全部线程都在运行workerCountOf(c) >= corePoolSize,所以此时将线程放到任务队列中
//判断线程池是否处于运行状态,且是否任务插入队列成功
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get(); ();//再次校验位
if (! isRunning(recheck) && remove(command)){ //线程池不是运行状态,并从workQueue(工作队列)中删除任务
reject(command); //抛出RejectedExceptionException异常
}else if (workerCountOf(recheck) == 0){ //线程池时是运行状态,从workQueue中删除任务失败(刚好有一个线程执行完毕,并消耗了这个任务),确保还有线程执行任务(只要有一个就够了)
addWorker(null, false); //创建工作进程 参数1为null时,表示新建一个线程;参数2为false时表示占用maxPoolSize;为true时表示占用corePoolSize
}
//3.线程池不是运行状态或者无法入队列尝试开启新线程,扩容至maxPoolSize,如果addWork(command, false)失败了
}else if (!addWorker(command, false)){
reject(command); //拒绝当前提交的执行任务
}
}
3.addWorker方法(用于添加Worker(工作线程))
参数的含义:
firstTask 线程的初始任务,可为空 ;
core true代表corePoolSize作为上线、false代表maximumPoolSize作为上线
private boolean addWorker(Runnable firstTask, boolean core) {
retry: //外层循环,负责判断线程池状态
for (;;) { //死循环
int c = ctl.get(); //当前运行线程的数量
int rs = runStateOf(c); //当前运行状态
// Check if queue empty only if necessary.
//当前运行状态不为RUNING,或者不在SHUTDOWN状态下(不接受新任务但是会执行完队列中的任务)
if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())){
return false; //否则返回false
}
for (;;) { //死循环
int wc = workerCountOf(c); //在检查一遍当前运行的线程数
//线程数不能大于最大容量,如果该任务标记为核心任务,线程数不能大于corePoolSize(核心线程),
//不然的话不能大于maximumPoolSize(最大线程数)
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)){
return false; //否则返回false
}
//将线程数加1,如果添加成功,则退出循环(失败一般都是因为线程数不同步)
if (compareAndIncrementWorkerCount(c)){
break retry;
}
c = ctl.get(); // Re-read ctl
//再检查一遍运行状态,如果运行状态改变了,将从外循环开头开始执行,再次确认能否添加任务
if (runStateOf(c) != rs){
continue retry;
}
// else CAS failed due to workerCount change; retry inner loop
//如果程序运行到这里,是因为线程数加1失败但是运行状态没有发生改变,此时会在执行内循环验证线程数
}
}
//下面的代码时创建新的worker(工作线程)实例
boolean workerStarted = false; //线程是否启动
boolean workerAdded = false; //worker(工作线程)是否已添加到Set中
Worker w = null;
try {
w = new Worker(firstTask); //将线程封装为Worker(工作线程)
final Thread t = w.thread; //worker(工作线程)实例中存放了一个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()); //线程池运行状态
//线程池处于运行状态,或者线程池关闭且任务线程为空
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) { //如果往HashSet中添加Worker(工作线程)成功
t.start(); //启动新线程
workerStarted = true;
}
}
} finally {
if (! workerStarted){ //未能成功创建执行工作线程
addWorkerFailed(w); // 在启动工作线程失败后,将工作线程从集合中删除
}
}
return workerStarted;
}
4.Worker方法 (用于设置锁状态并启动线程)
Worker实现了runnable有继承了AQS(AbstractQueuedSynchronizer),是个可执行认为又能实现锁的效果。
Worker和Task的区别:Worker是线程池中的线程,而Task虽然是runnable但并没有真正执行。
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
private static final long serialVersionUID = 6138294804551838833L;
final Thread thread; //利用TheadFactory和worker这个Runnable创建的线程对象
Runnable firstTask;
volatile long completedTasks;
Worker(Runnable firstTask) {
//设置AQS(AbstractQueuedSynchronizer不可冲入锁)初始状态
setState(-1); //-1不允许中断interrupt(),只有在worker线程启动了,并执行runWorker,将setState设置0才可中断
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);//根据当前worker创建线程对象
}
public void run() {
runWorker(this); //runWorker()方法是ThreadPoolExecutor的方法
}
// Lock methods
//
// The value 0 represents the unlocked state. 0 没被锁
// The value 1 represents the locked state. 1锁定
protected boolean isHeldExclusively() {
return getState() != 0;
}
//尝试获取锁(重写AQS的方法)
protected boolean tryAcquire(int unused) {
//尝试将state从0设置为1,即是锁定状态,但由于每次都是state 0->1,而不是+1,那么说明不可重入
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());//设置exclusiveOwnerThread=当前线程
return true;
}
return false;
}
//尝试释放锁并把状态设置为0
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
//如果运行中就中断,shutdownNow时会循环对worker线程执行且不需要获取worker锁
void interruptIfStarted() {
Thread t;
//如果state>=0、t!=null、且t没有被中断
//new Worker()时state==-1,说明不能中断
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
5.runWorker方法(用于启动线程)
该图来自:https://www.cnblogs.com/trust-freedom/p/6681948.html#label_3_1
执行过程:
a.Worker线程启动后,通过Worker类的run()方法调用runWorker(this).
b.执行任务之前,首先worker.unlock(),将AQS的state置为0,允许中断当前worker线程。
c.开始执行firstTask,调用task.run(),在执行任务前会上锁wroker.lock(),
在执行完任务后会解锁,为了防止在任务运行时被线程池一些中断操作中断。
d.在任务执行前后,可以根据业务场景自定义beforeExecute() 和 afterExecute()方法。
e.无论在beforeExecute()、task.run()、afterExecute()发生异常上抛,
都会导致worker线程终止,进入processWorkerExit()处理worker退出的流程。
f.如正常执行完当前task后,会通过getTask()从阻塞队列中获取新任务,
当队列中没有任务,且获取任务超时,那么当前worker也会进入退出流程。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true; //标识线程是不是异常终止的
try {
//task不为null情况是初始化worker时,如果task为null,则去队列中取线程--->getTask()
while (task != null || (task = getTask()) != null) {
w.lock();//上锁,不是为了防止并发执行任务,为了在shutdown()时不终止正在运行的worker
//1、如果线程池状态>=stop,且当前线程没有设置中断状态,wt.interrupt()
//2、如果一开始判断线程池状态=stop
//3、是,再次设置中断标示,wt.interrupt()
//4、否,不做操作,清除中断标示后进行后续步骤
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()){
wt.interrupt();//当前线程调用interrupt()中断
}
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);//这里就考验catch和finally的执行顺序了,因为要以thrown为参数
}
} finally {
task = null;//task置为null
w.completedTasks++;//完成任务数+1
w.unlock(); //解锁
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);//处理worker的退出
}
}
6.getTask方法 (用于从workQueue中获取任务)
图片来自:https://www.cnblogs.com/trust-freedom/p/6681948.html#label_3_1
private Runnable getTask() {
boolean timedOut = false; ;//轮询标志位,表明轮询是否超时
for (;;) { //死循环
int c = ctl.get();
int rs = runStateOf(c);
//线程池状态为非运行状态
//且
//或线程池处于STOP、TIDYING、TERMINATED
//或线程池已空
//这个时候将线程池的的计数减1
//由于线程池已空了,返回空
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();//循环的CAS减少worker数量,直到成功
return null;
}
int wc = workerCountOf(c);
//主要是标识着当前Worker超时是否要退出
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//当前线程池中线程数大于最大线程数 或 timed 且 timedOut均为true
//且
//当前线程数大于1,或 线程池中可用线程为空
if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
//若线程池中线程数成功减1
//返回空
//否则继续下一轮自旋
if (compareAndDecrementWorkerCount(c)){
return null;
}
continue;
}
try {
//通过timed变量来选择使用poll方法还是take方法
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
if (r != null){
return r;
}
timedOut = true; //如果poll获取的r为空,标记为超时
} catch (InterruptedException retry) {
timedOut = false; //响应中断,重新开始,中断状态会被清除
}
}
}
7、processWorkerExit方法 (从workers的Set中remove掉一个多余的线程)
参数含义:worker要结束的worker;completedAbruptly是否突然完成(是否因为异常退出)
private void processWorkerExit(Worker w, boolean completedAbruptly) {
/**
* 1、worker数量-1
* 如果是突然终止,说明是task执行时异常情况导致,即run()方法执行时发生了异常,那么正在工作的worker线程数量需要-1
* 如果不是突然终止,说明是worker线程没有task可执行了,不用-1,因为已经在getTask()方法中-1了
*/
if (completedAbruptly){
decrementWorkerCount();
}
/**
* 2、从Workers Set中移除worker
*/
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;//把worker的完成任务数加到线程池的完成任务数
workers.remove(w);//从HashSet中移除
} finally {
mainLock.unlock();//删除时需要上锁mainlock
}
/**
* 3、在对线程池有负效益的操作时,都需要“尝试终止”线程池
* 主要是判断线程池是否满足终止的状态
* 如果状态满足,但还有线程池还有线程,尝试对其发出中断响应,使其能进入退出流程
* 没有线程了,更新状态为tidying->terminated
*/
tryTerminate();
/**
* 4、是否需要增加worker线程
* 线程池状态是running 或 shutdown
* 如果当前线程是突然终止的,addWorker()
* 如果当前线程不是突然终止的,但当前线程数量 < 要维护的线程数量,addWorker()
* 故如果调用线程池shutdown(),直到workQueue为空前,线程池都会维持corePoolSize个线程,然后再逐渐销毁这corePoolSize个线程
*/
int c = ctl.get();
//如果状态是running、shutdown,即tryTerminate()没有成功终止线程池,尝试再添加一个worker
if (runStateLessThan(c, STOP)) {
//不是突然完成的,即没有task任务可以获取而完成的,计算min,并根据当前worker数量判断是否需要addWorker()
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;//allowCoreThreadTimeOut默认为false,即min默认为corePoolSize
//如果min为0,即不需要维持核心线程数量,且workQueue不为空,至少保持一个线程
if (min == 0 && ! workQueue.isEmpty()){
min = 1;
}
//如果线程数量大于最少数量,直接返回,否则下面至少要addWorker一个
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//添加一个没有firstTask的worker
//只要worker是completedAbruptly突然终止的,或者线程数量小于要维护的数量,就新添一个worker线程,即使是shutdown状态
addWorker(null, false);
}
}
8.tryTerminate方法(尝试下关闭线程池)
在addworker失败和work处理任务失败退出都涉及到线程,可能就剩下一个线程,此时就要尝试关闭线程池。
final void tryTerminate() {
for (;;) {
int c = ctl.get();
//1.线程池状态为Running
//2.状态已经是TIDYING或TERMINATED说明已经终止了
//3.SHUTDOWN但是队列不空还需要处理任务,不需要终止
if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())){
return;
}
// 到这里只剩下,shutdown状态队列空,Stop状态
if (workerCountOf(c) != 0) { // Eligible to terminate
//线程池还有线程,但是队列没有任务了,需要中断唤醒等待任务的线程(runwoker的时候首先就通过w.unlock设置线程可中断,
//getTask最后面的catch处理中断)
//中断空闲线程传入的true,唤醒一个等待线程来处理就行
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {//线程池状态转为TIDYING
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));//线程池状态转为TERMINATED
termination.signalAll();//awaitTermination的termination.awaitNanos(nanos)需要signal
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
到此线程池从创建、提交任务、结束、基本结束整个过程讲解完毕。
ThreadPoolExecutor生命周期
//1.推进状态到shutdown,不接受新任务(addworker时检查状态会控制)
//2.中断所有空闲线程,会检查线程池状态和队列是否空,保证已经提交的肯定会执行
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN); //推进线程池状态
interruptIdleWorkers(); //中断空闲的线程
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();//最后线程池尝试关闭下
}
2.shutdownNow方法(关闭线程,关闭所有正在执行的任务,并把任务以列表的方式返回)
//中断所有线程,不管是执行中还是getTask等待的,返回没执行的task列表
public List shutdownNow() {
List tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();//中断所有线程
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
备注:shutdown与shutdownNow的区别
不同点:
shutdown新的任务不会再被提交到线程池,但之前的都会依旧执行,
通过中断方式停止空闲的(根据没有获取锁来确定)线程。
shutdownNow则向所有正在执行的线程发出中断信号以尝试终止线程,
并将工作队列中的任务以列表方式的结果返回。
shutdown要将线程池推到SHUTDOWN状态。
shutdownNow要将线程池推到STOP状态。
相同点:
最后尝试将线程池推到TERMINATED状态。
3.awaitTermination方法(状态依赖的线程阻塞)
阻塞等待shutdown请求后所有线程终止,会有时间参数,超时和中断也会令方法调用结束,
实际就是Condition的定时await调用。
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
ThreadPoolExecutor生命周期的扩展点:
ThreadPoolExecutor为扩展类提供了一些扩展点,声明如下protected的方法
a、beforeExecute()在每个任务执行前做处理。
b、afterExecute()在每个任务执行后做处理。
c、terminated()在ThreadPoolExecutor到达TERMINATED状态前做处理。
d、finalize()有默认实现,直接调用shutdow(),以保证线程池对象回收。
e、onShutdown()在shutdown方法执行到最后时调用,在ScheduledThreadPoolExecutor类中使用。
f、扩展点,做一些任务队列的清理操作。
ThreadPoolExecutor的丢弃(也就是所谓的拒绝策略):
如果线程池的线程已饱和,并且任务队列已满,那么就会丢弃,为此使用RejectedExecutionHandler接口。
对RejectedExecutionHandler(拒绝策略)接口的解释:在使用线程池并使用有界队列时,如果队列满了,
任务添加到线程池就会有问题,为此提供了拒绝策略。策略有以下几种:
(1)、AbortPolicy:线程池默认的策略,如果任务添加到线程池失败,
会抛出RejectedExecutionException异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//不做任何处理,直接抛出异常
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " +e.toString());
}
(2)、DiscardPolicy:如果添加任务失败,则放弃,不会抛出任何异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//就是一个空的方法
}
(3)、DiscardOldesPolicy:如果任务添加到线程池失败,会将队列中最早添加的任务移除;
并再次尝试添加,如果添加失败则会继续按照该策略执行
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//移除队头元素
e.getQueue().poll();
//再尝试入队
e.execute(r);
}
}
(4)、CallerRunsPolicy:如果任务添加失败,主线程会自己调用执行器中的execute方法来执行该任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//直接执行run方法
r.run();
}
}
(5)、用户自定义策略:如果以上几种策略都不合适,将根据场景自定义拒绝策略,必须实现
RejectedExecutionHandler接口,并将自定义的逻辑写在rejectedExecution()方法中。
public class MyRejectPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//Sender是我的Runnable类,里面有message字段
if (r instanceof Sender) {
Sender sender = (Sender) r;
//直接打印
System.out.println(sender.getMessage());
}
}
}
至此:对ThreadPoolExecutor类的讲解已结束,由于该类比较复杂,java提供了一些简便方法(请查看五)
五、Executors工具类(主要提供线程池相关的操作)
该模块摘自:https://www.cnblogs.com/webglcn/p/5265901.html
Executors工具类提供了一些静态工厂方法,生成一些常用的线程池。总共有4中方法
1.newCachedThreadPool创建可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,
若无可回收,则新建线程。
2.newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的会在队列中等待。
3.newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor创建单线程的线程池,只能用唯一的工作线程来执行任务,保证所有
任务按照指定顺序(FIFO、LIFO、优先级)执行。
代码展示如下:
1. newCachedThreadPool创建可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,
若无可回收,则新建线程。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
}
}
线程池无限大,当执行第二个任务时第一个任务已完成,会复用执行第一个任务的线程,
而不用新建线程。
2.newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的会在队列中等待。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
因为线程池大小为3,每个任务输出index后sleep(睡)2秒,所以每两秒大于三个数字。
定长线程池大小最好根据系统资源配置,如Runtime.getRuntime().availableProcessors()
3.newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}
以上代码为延迟三秒执行
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
以上代码为定期执行;表示延迟1秒后每3秒执行一次
4.newSingleThreadExecutor创建单线程的线程池,只能用唯一的工作线程来执行任务,保证所有
任务按照指定顺序(FIFO、LIFO、优先级)执行。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
按照顺序执行每个任务
特别提醒:最后可以使用JDK自带的监控工具来监控我们创建的线程数量,运行一个不终止的线程,创建指定量的线程
来观察。
工具的路径:C:\Program Files\Java\jdk1.6.0_06\bin\jconsole.exe
稍微修改下程序代码
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
while(true) {
System.out.println(index);
Thread.sleep(10 * 1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
效果图如下:
选择我们的运行程序
监控状态