ThreadPoolExecutor executor = new ThreadPoolExecutor(0, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
try {
executor.execute(new Thread(new Runnable() {
@Override
public void run() {
System.out.println(1);
}
}));
}catch (Exception e){
e.printStackTrace();
}
源码入口executor.execute,点进去看看里面执行了什么
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//获取线程池的信息,ctl是一个32位的数字,高3位保存了线程池状态,低29位保存线程数量
int c = ctl.get();
//如果当前工作线程数少于核心线程,走下面这个逻辑,addWorker
if (workerCountOf(c) < corePoolSize) {
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);
}
//线程池非运行状态,或者任务入队失败,才会走到这个逻辑
//如果线程池非运行状态,是不能丢任务进去的,这个addWorker方法直接返回false,进入拒绝策略
//如果只是队列满,再尝试添加一次任务,如果添加失败,进入拒绝策略
else if (!addWorker(command, false))
reject(command);
}
addWorker()
先来看看addWorker做了什么
/**
* firsttask 提交的任务
* core 是否提交给核心线程工作
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();//获取线程池信息
int rs = runStateOf(c);//或者线程池运行状态信息
//运行状态在正常情况下一般都是高3位不动的,也就是负数,负很大
// 当线程状态大于等于SHUTDOWN(0)且(线程状态等于SHUTDOWN,提交的任务为null,任务队列不为空)这3个条件有一个不符合,都会走到false逻辑,也就是线程任务提交失败
//实际上,线程状态大于等于SHUTDOWN,也就是线程池进入了SHUTDOWN状态,一般情况下,只有通过shutdown()或者shutdownnow()方法才能进入
//shutdown()停止线程池,无法提交新任务了,但是旧存在的任务还是要执行完
//shutdownnow()也是停止线程池,但是池内原有任务直接被丢弃
//但是不管shutdown()还是shutdownnow(),新的任务都是无法添加,所以走到这都会return false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//获取线程池内工作线程数量
int wc = workerCountOf(c);
//如果任务提交给核心线程,判断当前核心线程满了么,满了return false;否则判断当前工作线程数是否超了最大线程数
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//cas去增加1工作线程数,如果自增成功,可以退出这个自旋逻辑,开始用这个线程执行任务啦
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // 为什么这里要再取一遍线程池状态?因为上一步CAS失败,说明其他线程优先执行了操作,对线程池的状态或者工作线程数量可能修改了,所以需要重取一遍
//如果线程状态变化,要重新走一遍最外层的逻辑
if (runStateOf(c) != rs)
continue retry;
//若无变化,则只是CAS竞争失败而已,重新进行自旋
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;//标记工作线程是否开始执行
boolean workerAdded = false;
Worker w = null;//Worker是什么?可以理解为消费者。线程池内维护了一个任务队列workQueue保存线程任务,workers是个hashset,保存了这些worker,也就是核心线程,最大线程的线程。
try {
//初始化一个新的工作线程,先往后看,看看Worker类里面放了什么
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());
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 {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
Worker类
很奇怪,为什么要把线程封装到worker中?线程池直接丢线程消费或者让线程去workQueue消费不就好了?实际上,使用worker类是为了更好的管理线程的中断
// 此处可以看出 worker 既是一个 Runnable 任务,也实现了 AQS(实际上是用 AQS 实现了一个独占锁,这样由于 worker 运行时会上锁,执行 shutdown,setCorePoolSize(),setMaximumPoolSize等方法时会试着中断线程(interruptIdleWorkers) ,在这个方法中断方法中会先尝试获取 worker 的锁,如果不成功,说明 worker 在运行中,此时会先让 worker 执行完任务再关闭 worker 的线程,实现优雅关闭线程的目的)
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
// 实际执行任务的线程
final Thread thread;
// 上文提到,如果当前线程数少于核心线程数,创建线程并将提交的任务交给 worker 处理处理,此时 firstTask 即为此提交的任务,如果 worker 从 workQueue 中获取任务,则 firstTask 为空
Runnable firstTask;
// 统计完成的任务数
volatile long completedTasks;
Worker(Runnable firstTask) {
// 初始化为 -1,这样在线程运行前(调用runWorker)禁止中断,在 interruptIfStarted() 方法中会判断 getState()>=0
setState(-1);
this.firstTask = firstTask;
// 根据线程池的 threadFactory 创建一个线程,将 worker 本身传给线程(因为 worker 实现了 Runnable 接口)
this.thread = getThreadFactory().newThread(this);
}
public void run() {
// thread 启动后会调用此方法
runWorker(this);
}
// 1 代表被锁住了,0 代表未锁
protected boolean isHeldExclusively() {
return getState() != 0;
}
// 尝试获取锁
protected boolean tryAcquire(int unused) {
// 从这里可以看出它是一个独占锁,因为当获取锁后,cas 设置 state 不可能成功,这里我们也能明白上文中将 state 设置为 -1 的作用,这种情况下永远不可能获取得锁,而 worker 要被中断首先必须获取锁
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 尝试释放锁
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(); }
// 中断线程,这个方法会被 shutdowNow 调用,从中可以看出 shutdownNow 要中断线程不需要获取锁,也就是说如果线程正在运行,照样会给你中断掉,所以一般来说我们不用 shutdowNow 来中断线程,太粗暴了,中断时线程很可能在执行任务,影响任务执行
void interruptIfStarted() {
Thread t;
// 中断也是有条件的,必须是 state >= 0 且 t != null 且线程未被中断
// 如果 state == -1 ,不执行中断,再次明白了为啥上文中 setState(-1) 的意义
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
runWorker()
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//unlock 会调用 tryRelease 方法将 state 设置成 0,代表允许中断
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//循环消费任务队列内任务,getTask()也是线程退出的一个核心方法
while (task != null || (task = getTask()) != null) {
w.lock();
//判断线程是否进入中断逻辑
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.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);
}
} finally {
task = null;
w.completedTasks++;//当前worker已消费的任务数+1
w.unlock();
}
}
completedAbruptly = false;
} finally {
//如果执行到这只有两种可能,一种是执行过程中异常中断了,一种是队列里没有任务了,从这里可以看出线程没有核心线程与非核心线程之分,哪个任务异常了或者正常退出了都会执行此方法,此方法会根据情况将线程数-1
processWorkerExit(w, completedAbruptly);
}
}
processWorkerExit()处理消费线程退出
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//如果线程异常退出,cas线程数-1
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
//加锁线程安全地移除工作线程
workers.remove(w);
} finally {
mainLock.unlock();
}
//工作线程退出,可能线程池状态变了,尝试关闭线程池
tryTerminate();
//重新获取线程池状态
int c = ctl.get();
//如果线程状态没到停止态
if (runStateLessThan(c, STOP)) {
//如果线程正常流程走下来,这个completedAbruptly是false,也就走进这个if逻辑
if (!completedAbruptly) {
//最小线程数,如果允许核心线程超时,就是0,不然就是核心线程数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1; //如果还有任务没消费完,那这个最小线程数可不能为0,至少为1
//如果当前的工作线程数大于最小线程数,说明有足够的线程在消费任务,就当无事发生
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//加入空任务,新建线程去消费
addWorker(null, false);
}
}
到此为止,考虑的情况都是池内线程数小于核心线程数。接下来考虑池内线程数大于核心线程数,也就是
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
addWorker方法返回了false。现在核心线程的任务丢不进去了,回到execute方法的第3个if
if(isRunning© && workQueue.offer(command))
显然正常状态下,任务队列不满,这个逻辑就是直接把任务丢进队列,结束~,队列里的任务有核心线程在消费咯(getTask()方法)。
核心线程or非核心线程是怎么下线的?
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
//获取线程池状态
int c = ctl.get();
//获取线程池运行信息
int rs = runStateOf(c);
// 如果线程池SHUTDOWN了,且已经停或者队列空,减1工作线程数,结束当前gettask
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 若满足允许核心线程超时或工作线程数大于核心线程数,则timed=true
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//如果线程数大于最大线程数或者都超时且
if ((wc > maximumPoolSize || (timed && timedOut))
//表示工作线程不止这个或者队列为空,那没有工作线程也没关系
&& (wc > 1 || workQueue.isEmpty())) {
//减少工作线程
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//从任务线程里取任务,如果timed,则进入回收策略,在超时时间内都没有取到任务的话,证明不需要这个线程啦,下次循环,工作线程数-1
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
至于这个worker,在后续的processWorkerExit()方法内被移除