深入理解线程池源码逐行解析(强烈建议收藏)

深入理解线程池源码需要拆解其核心组件和工作流程。下面是对其源码关键部分的结构化解析以及线程池(以Java ThreadPoolExecutor 为例)的完整工作流程图和关键步骤说明:

一、整体流程


提交任务 execute
当前线程数 < corePoolSize?
创建核心线程执行任务
任务入队成功?
需补充线程?
创建非核心线程处理队列
等待线程处理
当前线程数 < maximumPoolSize?
创建非核心线程执行任务
执行拒绝策略
执行任务 runWorker
任务队列非空?
获取任务 getTask
判断线程回收
需回收线程?
线程退出

详细流程说明:

  1. 任务提交阶段

    • execute(Runnable command) 入口
    • 优先创建核心线程(workerCount < corePoolSize
    • 次优尝试任务入队(workQueue.offer()
    • 队列满时尝试创建非核心线程(workerCount < maximumPoolSize
    • 所有路径失败时触发拒绝策略
  2. 线程执行阶段

    • runWorker(Worker w) 核心循环
    • 先执行初始任务(firstTask
    • 循环调用 getTask() 获取队列任务
    • 执行前后触发钩子函数(beforeExecute/afterExecute
    • 加锁保证任务执行原子性(Worker实现AQS锁)
  3. 任务获取阶段

    • getTask() 关键逻辑:
    • 判断线程池状态(SHUTDOWN/STOP时返回null)
    • 核心线程使用workQueue.take()(永久阻塞)
    • 非核心线程使用workQueue.poll(keepAliveTime)(超时等待)
    • 超时或线程超额时返回null触发回收
  4. 线程回收阶段

    • 非核心线程超时无任务时触发回收
    • 线程退出前调用processWorkerExit()
    • 尝试补充线程(避免SHUTDOWN状态无线程处理队列)
    • 状态转换至TIDYING时触发terminated()钩子

状态流转示意图:

RUNNING:
创建线程池
RUNNING
SHUTDOWN:
调用shutdown()
STOP:
调用shutdownNow()
SHUTDOWN
再次调用shutdownNow()
TIDYING:
任务队列空且工作线程=0
STOP
工作线程=0
TIDYING
TERMINATED:
terminated()执行完毕
TERMINATED

关键设计特点:

动态线程调节

  • 核心线程常驻(默认)
  • 非核心线程借出机制(超时回收)
  • 应急线程创建(队列满时)

3优雅退出机制

  • SHUTDOWN模式:消化存量任务
  • STOP模式:立即中断+丢弃队列
  • TIDYING状态:清理前的最后一站

异常处理流程:

任务执行异常
传播到runWorker
记录异常信息
触发afterExecute hook
是否线程退出
processWorkerExit
继续获取任务

理解此流程可解决:

  • 任务堆积诊断(队列选型不当)
  • 线程泄漏问题(异常未捕获)
  • 资源竞争优化(Worker锁粒度)
  • 优雅停机实现(状态机转换)

二、源码解析

核心成员变量

public class ThreadPoolExecutor extends AbstractExecutorService {
    // 核心:合并存储线程池状态 (runState) 和工作线程数 (workerCount)
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 
    private static final int COUNT_BITS = 29; // 32位中低29位存线程数
    private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 最大线程数 (536870911)

    // 线程池状态(高3位存储)
    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; // 所有任务终止,workerCount=0,将执行terminated()
    private static final int TERMINATED =  3 << COUNT_BITS; // terminated() 执行完成

    // 阻塞队列 & 线程工厂
    private final BlockingQueue<Runnable> workQueue;
    private final ThreadFactory threadFactory;
    
    // 拒绝策略 & 非核心线程存活时间
    private volatile RejectedExecutionHandler handler;
    private volatile long keepAliveTime;
    private volatile int corePoolSize;
    private volatile int maximumPoolSize;
    
    // 工作线程集合(需要同步访问)
    private final HashSet<Worker> workers = new HashSet<>();
}

核心类:Worker

private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
    final Thread thread; // Worker持有的线程
    Runnable firstTask;  // 初始任务(可为null)
    volatile long completedTasks; // 完成任务计数

    Worker(Runnable firstTask) {
        setState(-1); // 禁止中断,直到runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this); // 将自己作为Runnable传给新线程
    }

    public void run() {
        runWorker(this); // 核心执行逻辑
    }

    // 实现AQS锁(非重入锁)
    protected boolean isHeldExclusively() { ... }
    protected boolean tryAcquire(int unused) { ... }
    protected boolean tryRelease(int unused) { ... }
}

任务执行流程:execute(Runnable command)

public void execute(Runnable command) {
    if (command == null) throw new NullPointerException();
    int c = ctl.get();

    // 1. 当前线程数 < corePoolSize
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true)) // 创建核心线程执行任务
            return;
        c = ctl.get(); // 若addWorker失败,重新获取ctl
    }

    // 2. 线程池运行中且任务入队成功
    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); // 确保至少有一个线程处理队列任务
    }
    // 3. 尝试创建非核心线程执行任务(若失败则拒绝)
    else if (!addWorker(command, false))
        reject(command);
}

线程执行核心:runWorker(Worker w)

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // 允许中断
    boolean completedAbruptly = true;
    try {
        // 循环获取任务(优先执行firstTask,之后从队列取)
        while (task != null || (task = getTask()) != null) {
            w.lock(); // 加锁确保任务执行不被中断
            // 检查线程池状态(若STOP则确保线程被中断)
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) {
                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); // 清理线程退出
    }
}

任务获取:getTask()

private Runnable getTask() {
    boolean timedOut = false; // 上次poll是否超时?
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // 1. 线程池已关闭且队列为空 → 返回null
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);
        // 2. 判断是否需要淘汰线程(允许核心线程超时 或 wc > corePoolSize)
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        // 3. 两种情况返回null(触发线程回收):
        //   a) 线程数超过maximumPoolSize
        //   b) 线程空闲超时(timed && timedOut)
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            // 4. 从队列取任务(超时控制)
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true; // 标记超时
        } catch (InterruptedException retry) {
            timedOut = false; // 中断重试
        }
    }
}

拒绝策略(RejectedExecutionHandler)

内置四种策略:

  1. AbortPolicy(默认):抛出 RejectedExecutionException
  2. CallerRunsPolicy:调用者线程直接执行任务
  3. DiscardPolicy:静默丢弃任务
  4. DiscardOldestPolicy:丢弃队列头任务,重试提交

线程池状态转换

RUNNING
SHUTDOWN:
shutdown()
STOP:
shutdownNow()
SHUTDOWN
TIDYING:
队列空且线程数=0
STOP
线程数=0
TIDYING
TERMINATED:
terminated()执行完毕

关键设计思想

  1. 位压缩(ctl):用单变量同时存储状态和线程数,避免竞态条件
  2. Worker锁:通过AQS实现非重入锁,控制任务执行期间的中断
  3. 动态线程管理getTask() 中的超时机制实现非核心线程回收
  4. 柔性关闭shutdown() 优雅处理队列任务,shutdownNow() 暴力中断

常见问题 & 调优建议

  1. 线程泄漏:确保任务抛异常时线程能回收(afterExecute 捕获异常)
  2. 队列选择
    • SynchronousQueue:直接传递(适用于短任务、高吞吐)
    • LinkedBlockingQueue:无界队列(需警惕OOM)
    • ArrayBlockingQueue:有界队列(需配合合理拒绝策略)
  3. 核心参数
    • CPU密集型corePoolSize = CPU核数 + 1
    • IO密集型corePoolSize = 2 * CPU核数
  4. 监控:重写 beforeExecute/afterExecute 添加日志/指标统计

理解线程池源码能帮助开发者规避资源耗尽、任务堆积等问题,并根据场景灵活定制线程池行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值