问题
咱们先聊三个问题,带着问题看源码:
- 线程池如何保持核心线程不消亡?
- 如果核心线程数量为0,新的任务先入队还是直接运行?最终线程池是否会走向消亡?
- 允许核心线程超时,影响点在哪?.
示例
自定义线程池
class MyThreadPool extends ThreadPoolExecutor {
public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println("执行前!!");
super.beforeExecute(t, r);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("执行后!!!");
super.afterExecute(r, t);
}
}
示例
public ThreadPoolExecutor getThreadPool() {
return new MyThreadPool(0,
10,
5,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10000));
}
public static void main(String[] args) {
ThreadPoolExecutor threadPool = new Demo().getThreadPool();
for (int i = 0; i < 1; i++) {
threadPool.execute(() -> {
System.out.println("执行任务中");
});
}
}
结果
源码分析
前置知识
/**
* rs: 线程池运行状态,包括RUNNING SHUTDOWN STOP TYDYING TERMINATED
* wc: 线程池中正在运行的线程数量
* private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // ctl贯穿整个线程池,这里采用高 3 位来保存运行状态,低 29 位来保存线程数量
* private static final int COUNT_BITS = Integer.SIZE - 3; //32-3
* private static final int CAPACITY = (1 << COUNT_BITS) - 1; //将 1 的二进制向右位移 29 位,再减 1 表示最大线程容量
*
* //运行状态保存在 int 值的高 3 位 (所有数值左移 29 位)
* private static final int RUNNING = -1 << COUNT_BITS;// 接收新任务,并执行队列中的任务
* private static final int SHUTDOWN = 0 << COUNT_BITS;// 不接收新任务,但是执行队列中的任务
* private static final int STOP = 1 << COUNT_BITS;// 不接收新任务,不执行队列中的任务,中断正在执行中的任务
* private static final int TIDYING = 2 << COUNT_BITS; //所有的任务都已结束,线程数量为 0,处于该状态的线程池即将调用 terminated()方法
* private static final int TERMINATED = 3 << COUNT_BITS;// terminated()方法执行完成
*
*
*/
入口
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 获取线程池运行状态
int c = ctl.get();
// corePoolSize = 0,这个if不会进入
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);
else if (workerCountOf(recheck) == 0)
// 从队列拿任务,使用线程工厂新建线程,执行任务
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
addWorker
新建一个worker对象,包括新建一个线程对象
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
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
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 新建一个线程任务
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) {
// 启动线程,对应的是Worker的run方法
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
runWorker
运行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 {
// 从worker中拿新任务或者从队列里拿任务
// getTask()支持超时返回,由 allowCoreThreadTimeOut || wc > corePoolSize 决定
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 {
// 钩子方法,在执行任务前执行,默认是一个抽象方法,规范需要在子类重写这个方法的同时,调用super.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 {
// 钩子方法,在执行任务后执行,默认是一个抽象方法,规范需要在子类重写这个方法的同时,调用super.afterExecute方法,达到支持层级拓展的目的
afterExecute(task, thrown);
}
} finally {
// 当前任务执行完一次后,后续从阻塞队列拿任务
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// while(...)条件不满足时,对即将结束的线程做处理,包括判断是否改变线程池状态等
processWorkerExit(w, completedAbruptly);
}
}
getTask
从队列中获取任务,支持超时机制
private Runnable getTask() {
boolean timedOut = false;
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);
// 是否启动超时机制,由allowCoreThreadTimeOut或核心线程数影响
// 当设置allowCoreThreadTimeOut = true 或者corePoolSize = 0 时,启动超时机制
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 如果上一次循环,没有拿到任务,此次timedOut = true
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果在固定时间内没有拿到任务,设置timedOut = true,进入下一次循环,如果仍然没有任务,
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
总结
回到最初的几个问题:
线程池如何保持核心线程不消亡?
通过阻塞队列take方法阻塞核心线程(不开启超时)
如果核心线程数量为0,新的任务先入队还是直接运行?最终线程池是否会走向消亡?
核心线程为0,新的任务先入队,然后线程从队列中获取任务。最终线程池会走向消亡,因为从队列获取任务的方法getTask是支持超时机制的,如果此时队列没有任务,由于核心线程为0,timed = true,最终线程池走向消亡。
允许核心线程超时,影响点在哪?
主要影响点是getTask(),timed恒为true,.该方法启动超时机制,同一线程如果长时间没有获取到任务,最终线程走向消亡。
Thread类的exit()什么时候调用
这个方法是JVM调用的,在线程消亡前,释放线程占有的资源。在Java定义只是提供一个JVM调用入口,后续允许JDK拓展这个方法。
// 给即将消亡的线程一次机会去清理自己占用的资源
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}