线程池的作用
线程池的作用主要有以下几种,分别是减少线程的开销、异步执行代码、简化线程管理等。线程池减少线程的开销主要的原因是 JVM 的线程与内核线程是 1:1 的,也就是说创建一个线程需要创建一个内核线程。什么是内核线程,内核线程代表的是由操作系统内核直接调度和管理的线程,由操作系统进行任务调度的基本单位。内核线程的创建、调度和销毁均由操作系统负责。内核维护其上下文,并决定何时在 CPU 去执行。所以创建或者销毁一个线程是比较大的开销。使用线程池可以重复利用线程,减少开销。
线程池源码分析
1、核心变量与状态控制
ThreadPoolExecutor 用 ctl 变(AtomicInteger)同时存储线程池状态和线程数量。通过位运算高效管理。
// 高3位存储线程池状态(RUNNING, SHUTDOWN, etc.),低29位存储工作线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 状态常量(二进制高3位)
private static final int RUNNING = -1 << COUNT_BITS; // 111 00000...
private static final int SHUTDOWN = 0 << COUNT_BITS; // 000 00000...
private static final int STOP = 1 << COUNT_BITS; // 001 00000...
private static final int TIDYING = 2 << COUNT_BITS; // 010 00000...
private static final int TERMINATED = 3 << COUNT_BITS; // 011 00000...
// 解析线程池状态和线程数的方法
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
状态流转为:RUNNING -> SHUTDOWN -> STOP -> TIDYING -> TERMINATED
- RUNNING:接受新任务,也能处理阻塞队列中的任务
- SHUTDOWN:不接受新任务,但是处理阻塞队列中的任务
- STOP:不接受新任务,也不处理阻塞队列中的任务,中断处理过程中的任务
- TIDYING:当所有的任务都执行完了,当前线程池中已经没有工作线程,这时线程池会转换为 TIDYING 状态,并且要调用 terminated 方法
- TERMINATED:terminated 方法调用完成
2、Worker 线程管理
Worker 类封装了工作线程,继承了 AQS(AbstractQueuedSynchronizer),实现不可重入锁,用于防止任务执行期间被中断
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread; // 实际执行任务的线程(由ThreadFactory创建)
Runnable firstTask; // 初始任务(可能为null)
Worker(Runnable firstTask) {
setState(-1); // 初始状态禁止中断,直到调用runWorker()
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); // 通过工厂创建线程
}
public void run() {
runWorker(this); // 核心执行逻辑(见下文)
}
// 通过AQS实现锁机制
protected boolean isHeldExclusively() { return getState() != 0; }
protected boolean tryAcquire(int unused) { /* ... */ }
protected boolean tryRelease(int unused) { /* ... */ }
}
3、核心方法 runWorker
每个 Worker 线程在 runWorker() 中循环获取并执行任务。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 允许中断
boolean completedAbruptly = true;
try {
// 循环获取任务:先从firstTask取,再从队列中poll/take
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); // 钩子方法(可扩展)
try {
task.run(); // 执行任务(注意:此处是直接调用,非新线程)
afterExecute(task, null); // 钩子方法
} catch (Throwable ex) {
afterExecute(task, ex); // 异常处理钩子
throw ex;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly); // Worker退出清理逻辑
}
}
4、任务获取 getTask()
线程从阻塞队列中获取任务,根据配置决定是否超时等待。
private Runnable getTask() {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 检查线程池是否已关闭且队列为空,若满足则返回null,Worker退出
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 线程数超过maximumPoolSize或需要超时回收,且超时未获取任务,减少Worker数量
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
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; // 超时标记
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
5、任务提交 execute()
任务提交的核心逻辑,决定是直接执行、入队还是拒绝。
public void execute(Runnable command) {
if (command == null) throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { // 当前线程数 < corePoolSize
if (addWorker(command, true)) // 尝试创建新Worker(核心线程)
return;
c = ctl.get(); // 如果addWorker失败(如线程池已关闭),重新获取状态
}
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); // 队列满且线程数已达maximumPoolSize,触发拒绝策略
}