关键构造属性:
volatile int runState; 保证了多线程的共享可见性
static final int RUNNING = 0;
static final int SHUTDOWN = 1; 运行了SHUTDOWN
static final int STOP = 2; 运行了SHUTDOWNNOW
static final int TERMINATED = 3; 线程池销毁最终状态
private final BlockingQueue
private final ReentrantLock mainLock = new ReentrantLock();//在新增加线程,和销毁线程时保证原子性和共享性
private final HashSet
实现原理:在新提交一个任务时,如果线程池线程数量
在调用shutdown时,把线程池的状态变更为SHUTDOWN ,同时把非工作中线程进行中断(通过轮询workers, tryLock取得work的锁进行设置中断,工作的线程无法获得锁)。不在接受新任务(因为线程池状态为SHUTDOWN ,接受任何后会传送给拒绝策略),接受新任务会传递给阻止策略;把队列中的任务运行完毕,如果队列任务运行完毕,轮询Workers把空闲线程设置中断,由于并移除workers(由于取不到任务退出while循环进入到workerDone),如果池中线程为0,会尝试把线程池变更为TERMINATED 状态。
在调用shutdownnow时,把线程池的状态变更为STOP ,同时把所有池中线程轮询进行设置中断。不在接受新任务,不在运行队列中的任务,把运行中任务设置线程中断标志,消亡线程,如果池中线程为0,会尝试把线程池变更为TERMINATED 状态,把workQueue工作队列中任务移除到Arraylist集合并返回。
小提醒:
thread的interrupt方法仅仅是线程的中断标示,某些阻塞方法如thread.sleep join wait及某些IO操作会响应中断并抛出中断异常。如果运行的任务有异常导致线程死亡,通过这里会把死亡线程移除。finally里的workerDone(this),确保了线程池溢出线程进行清理掉。
一、构造:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue
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;//线程拒绝策略
}
二、线程池运行任务
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {//如果目前线程数大于核心线程数执行下面的添加到工作队列;否则为目前线程数小于核心线程数,创建核心线程并执行。
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)//因为上面的添加到队列为无锁状态添加,不能确保一致性,所有添加后再次检查线程池是否Running状态,如果不在把当前任务应用于拒绝策略。
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))//如果队列已经满,继续创建线程并完成任务。
reject(command); // is shutdown or saturated
}
}
private boolean addIfUnderCorePoolSize(Runnable firstTask) {
Thread t = null;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//获得锁
try {
if (poolSize < corePoolSize && runState == RUNNING)
t = addThread(firstTask);//添加线程并启动任务
} finally {
mainLock.unlock();
}
return t != null;
}
private Thread addThread(Runnable firstTask) {
Worker w = new Worker(firstTask);//形成工作任务者
Thread t = threadFactory.newThread(w);
boolean workerStarted = false;
if (t != null) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
w.thread = t;
workers.add(w);//保存所有工作任务者
int nt = ++poolSize;
if (nt > largestPoolSize)
largestPoolSize = nt;
try {
t.start();//启动工作任务者,完成任务工作
workerStarted = true;
}
finally {
if (!workerStarted)
workers.remove(w);
}
}
return t;
}
----------------------------------------------------------------------------
private final class Worker implements Runnable {
public void run() {//工作者被Start启动时运行该方法
try {
hasRun = true;
Runnable task = firstTask;
firstTask = null;
while (task != null || (task = getTask()) != null) {//如果新创建线程firstTask有任务进行下面的运行,第一个任务运行完了,通过getTask()从队列取任务再次运行
runTask(task);//把任务的run方法重新包装了一下,通过模板方式在任务运行前和运行后添加了附加操作
task = null;
}
} finally {//放到finally里的好处是,无论何种情况没有取到任务脱离while循环,都会把脱离循环的线程从线程池移除。如果运行的任务有异常导致线程死亡,通过这里会把死亡线程移除。
workerDone(this);//如果从队列了没有取到任务,把线程从线程池里移除。
}
}
private void runTask(Runnable task) {
final ReentrantLock runLock = this.runLock;
runLock.lock();//获得本线程的锁,表示正在运行任务
try {
/*
* If pool is stopping ensure thread is interrupted;
* if not, ensure thread is not interrupted. This requires
* a double-check of state in case the interrupt was
* cleared concurrently with a shutdownNow -- if so,
* the interrupt is re-enabled.
*/
//下面这里说明如果现在运行了shutdownnow,检测到interrupted()为true只是把线程的中断标志设置,并不中断线程继续运行。
if ((runState >= STOP ||
(Thread.interrupted() && runState >= STOP)) &&
hasRun)
thread.interrupt();
/*
* Track execution state to ensure that afterExecute
* is called only if task completed or threw
* exception. Otherwise, the caught runtime exception
* will have been thrown by afterExecute itself, in
* which case we don't want to call it again.
*/
boolean ran = false;
beforeExecute(thread, task);//运行前置方法
try {
task.run();//运行任务的实际方法
ran = true;
afterExecute(task, null);//运行后置方法
++completedTasks;
} catch (RuntimeException ex) {
if (!ran)
afterExecute(task, ex);
throw ex;
}
} finally {
runLock.unlock();
}
}
Runnable getTask() {
for (;;) {
try {
int state = runState;
if (state > SHUTDOWN)//如果现在已经运行了shundownnow现在不能再从队列取任务了
return null;
Runnable r;
if (state == SHUTDOWN) // Help drain queue
r = workQueue.poll();//非阻塞获取
else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);//阻塞一定时间内获取
else
r = workQueue.take();//阻塞获取
if (r != null)
return r;
if (workerCanExit()) {//判断是否要中断线程
if (runState >= SHUTDOWN) // Wake up others
interruptIdleWorkers();//中断目前非正在工作中的线程
return null;
}
// Else retry
} catch (InterruptedException ie) {
// On interruption, re-check runState
}
}
}
void interruptIfIdle() {
final ReentrantLock runLock = this.runLock;
if (runLock.tryLock()) {//如果可以获取到线程锁,说明目前线程没有正在工作中
try {
if (hasRun && thread != Thread.currentThread())
thread.interrupt();
} finally {
runLock.unlock();
}
}
}
void workerDone(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);//删除线程池里的线程
if (--poolSize == 0)//如果线程池中线程已经为0,会改变线程池状态为Terminate
tryTerminate();
} finally {
mainLock.unlock();
}
}
-------------------------------
1、shutdown()
问:shutdown()有什么功能?
答:阻止新来的任务提交,对已经提交了的任务不会产生任何影响。它会将那些闲置的线程(idleWorks)进行中断,当已经提交的任务执行完后,进行把线程中断设置线程池TERMINATED 状态。
问:如何阻止新来的任务提交?
答:通过将线程池的状态改成SHUTDOWN,当再将执行execute提交任务时,如果测试到状态不为RUNNING,则传递给阻止策略,从而达到阻止新任务提交的目的。
问:为何对提交的任务不产生任何影响?
答:在调用中断任务的方法时,它会检测workers中的任务尝试获得work的锁trylock才进行中断,如果work正在工作无法获得锁无法进行中断,活动的work会一直把队列中的任务执行完毕后,才设置中断。
2、shutdownNow()
问:shutdownNow()有什么功能?
答:阻止新来的任务提交,同时会中断当前正在运行的线程,即workers中的线程。另外它还将workQueue中的任务给移除,并将这些任务添加到列表中进行返回。
问:如何阻止新来的任务提交?
答:通过将线程池的状态改成STOP,当再将执行execute提交任务时,如果测试到状态不为RUNNING,则传递给阻止策略,从而达到阻止新任务提交的目的.
问:如果我提交的任务代码块中,正在等待某个资源,而这个资源没到,但此时执行shutdownNow(),会出现什么情况?
答:当执行shutdownNow()方法时,如遇已经激活的任务,并且处于阻塞状态时, 如果阻塞不接受中断会一直阻塞直到获得资源完成;如果当前阻塞接受中断会抛出InterruptedException。, shutdownNow()会执行1次中断阻塞的操作,此时对应的线程报InterruptedException,如果后续还要等待某个资源,则按正常逻辑等待某个资源的到达。例如,一个线程正在sleep状态中,此时执行shutdownNow(),它向该线程发起interrupt()请求,而sleep()方法遇到有interrupt()请求时,会抛出InterruptedException(),并继续往下执行。
3、awaitTermination(long timeout,TimeUnit unit)
简单来说,awaitTermination会一直等待,直到线程池状态为TERMINATED或者等待的时间到达了指定的时间。如果此执行程序终止,则返回 true;如果终止前超时期满,则返回 false。
客户端线程和线程池之间会有一个任务队列。当程序要关闭时,你需要注意两件事情:入队的这些任务的情况怎么样了以及正在运行的这个任务执行得如 何了。令人惊讶的是很多开发人员并没能正确地或者有意识地去关闭线程池。正确的方法有两种:一个是让所有的入队任务都执行完毕(shutdown()), 再就是舍弃这些任务(shutdownNow())——这完全取决于你。比如说如果我们提交了N多任务并且希望等它们都执行完后才返回的话,那么就使用 shutdown():
private void sendAllEmails(List emails) throws InterruptedException {
emails.forEach(email ->
executorService.submit(() ->
sendEmail(email))); executorService.shutdown(); final boolean done = executorService.awaitTermination(1, TimeUnit.MINUTES); log.debug("All e-mails were sent so far? {}", done); }
本例中我们发送了许多电子邮件,每一封邮件都对应着线程池中的一个任务。提交完这些任务后我们会关闭线程池,这样就不会再有新的任务进来了。然 后我们会至少等待一分钟,直到这些任务执行完。如果1分钟后还是有的任务没执行到的话,awaitTermination()便会返回false。但是剩 下的任务还会继续执行。
参考:https://www.cnblogs.com/langtianya/p/4520373.html