Java 线程池(ThreadPoolExecutor)源码分析

22 阅读7分钟

Java 线程池(ThreadPoolExecutor)源码分析

一、整体结构

ThreadPoolExecutor
├── 核心参数:corePoolSize、maximumPoolSize、workQueue、keepAliveTime、threadFactory、handler
├── 状态:ctl (AtomicInteger,高3位状态 + 低29位线程数)
├── 工作线程:Worker(继承 AQS,实现 Runnable)
└── 任务队列:BlockingQueue<Runnable>

二、execute():提交任务入口

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    
    int c = ctl.get();
    // 步骤1:当前线程数 < 核心线程数 → 创建核心线程执行
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 步骤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);
        return;
    }
    // 步骤3:队列满,尝试创建非核心线程
    if (!addWorker(command, false))
        reject(command);  // 步骤4:创建失败,执行拒绝策略
}

步骤说明

步骤逻辑说明原因
1workerCountOf(c) < corePoolSize当前工作线程数小于核心线程数核心线程是常驻的,优先用核心线程执行,减少线程创建开销
1.1addWorker(command, true)创建核心线程并执行该任务核心线程不足时立即创建,firstTask 直接交给新线程执行,无需入队
2workQueue.offer(command)线程数已满,尝试把任务放入队列核心线程已满时先入队等待,队列有界时可控制背压,避免无限制创建线程
2.1isRunning(recheck)再次检查池是否还在运行,防止并发下状态变化入队与取任务存在并发,可能在此期间调用了 shutdown,需 double-check 避免向已关闭池提交
2.2workerCountOf(recheck) == 0若没有工作线程,补一个空任务 Worker,保证队列任务能被消费可能所有 Worker 已退出,但队列还有任务,需补 Worker 否则任务永远无法执行
3addWorker(command, false)队列已满,尝试创建非核心线程执行任务队列满说明负载高,临时扩容到 maximumPoolSize 以应对峰值
4reject(command)线程数已达 maximumPoolSize,执行拒绝策略池已满,按 RejectedExecutionHandler 策略处理(抛异常、丢弃、调用者执行等)

三、addWorker():添加工作线程

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // 步骤1:检查线程池状态
        if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
            return false;
        for (;;) {
            int wc = workerCountOf(c);
            // 步骤2:检查线程数是否超限
            if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();
            if (runStateOf(c) != rs)
                continue retry;
        }
    }
    // 步骤3:创建 Worker 并加入 workers 集合
    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 {
                int rs = runStateOf(ctl.get());
                if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive())
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();  // 步骤4:启动线程
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

步骤说明

步骤逻辑说明原因
1rs >= SHUTDOWN 判断若已 SHUTDOWN/STOP/TIDYING/TERMINATED,一般不再接受新任务关闭后不应再创建新 Worker,避免资源浪费和状态混乱
1.1特殊:SHUTDOWN && firstTask==null && !workQueue.isEmpty()允许添加「空任务」Worker 去消费队列剩余任务shutdown 后不再接新任务,但需把队列中已有任务执行完,空 Worker 会通过 getTask 取队列任务
2wc >= corePoolSizemaximumPoolSize核心/非核心线程数已达上限,不再创建防止超过配置的线程数,保证资源可控
2.1compareAndIncrementWorkerCount(c)CAS 增加工作线程计数,避免并发超限多线程并发 execute 时,CAS 保证 workerCount 准确,防止超卖
3new Worker(firstTask)workers.add(w)创建 Worker,加入 workers 集合Worker 封装线程与任务,workers 用于 shutdown 时遍历中断
4t.start()启动 Worker 内部线程,进入 runWorker()线程启动后进入循环取任务、执行任务的流程

四、Worker:工作线程封装

private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
    final Thread thread;      // 实际执行任务的线程
    Runnable firstTask;       // 创建时分配的第一个任务(可为 null)
    
    Worker(Runnable firstTask) {
        setState(-1);  // 初始状态,防止被中断
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);  // 把自己作为 Runnable
    }
    
    public void run() {
        runWorker(this);  // 委托给 runWorker
    }
}

步骤说明

步骤逻辑说明原因
1setState(-1)初始 AQS 状态为 -1防止 Worker 刚创建时被误判为可中断,runWorker 中 unlock 后才允许中断
2getThreadFactory().newThread(this)用线程工厂创建线程,this 作为 Runnable统一线程创建方式,Worker 的 run 会调用 runWorker,形成执行入口
3继承 AQS实现简单锁区分空闲(lock 前)与工作中(lock 后),shutdown 时只中断空闲 Worker,避免打断正在执行的任务

五、runWorker():工作线程主循环

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock();  // 允许中断
    boolean completedAbruptly = true;
    try {
        // 步骤1:循环取任务(firstTask 或 getTask())
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // 步骤2:检查是否需要中断(shutdown 等)
            if ((runStateAtLeast(ctl.get(), STOP) || 
                 (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);  // 钩子
                try {
                    task.run();  // 步骤3:执行任务
                } finally {
                    afterExecute(task, thrown);  // 钩子
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);  // 步骤4:Worker 退出处理
    }
}

步骤说明

步骤逻辑说明原因
1task = w.firstTaskgetTask()优先执行创建时传入的 firstTask,之后从队列取任务firstTask 是 addWorker 时传入的,直接执行可少一次入队出队;之后从队列取任务实现复用
2状态检查 + 中断若池已 STOP 或当前线程被中断,确保线程被中断,以便快速退出STOP 时要尽快结束,中断可让阻塞在 getTask 的线程及时退出
3task.run()直接执行任务(不是 start(),复用当前线程)Worker 线程就是工作线程,直接 run 在当前线程执行,无需再起新线程
4processWorkerExit()线程退出时:减少 worker 计数、必要时补充新 Worker、尝试终止线程池保证 workerCount 正确,SHUTDOWN 时若队列非空可补 Worker,最终尝试转为 TERMINATED

六、getTask():从队列取任务

private Runnable getTask() {
    boolean timedOut = false;
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // 步骤1:池已关闭且队列空,直接返回 null
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount(c);
            return null;
        }
        int wc = workerCountOf(c);
        // 步骤2:是否允许超时回收(非核心 或 允许核心超时)
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        try {
            // 步骤3:阻塞取任务(带超时或不带超时)
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

步骤说明

步骤逻辑说明原因
1rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())池已关闭,且要么已 STOP,要么队列已空,不再取任务STOP 时不处理队列;SHUTDOWN 时队列空才退出,保证队列任务被消费完
2timed = allowCoreThreadTimeOut || wc > corePoolSize超过核心数的线程或允许核心超时时,使用超时取任务非核心线程空闲超过 keepAliveTime 应回收;核心线程在 allowCoreThreadTimeOut 时也可回收
2.1wc > maximumPoolSize(timed && timedOut)线程数超限或上次取任务超时,且满足回收条件时,减少 worker 并返回 null扩容后负载下降需缩容;超时取到 null 表示空闲过久,可回收以释放资源
3poll(keepAliveTime) / take()超时取或阻塞取,超时返回 null 会触发 timedOut = true,下次循环可能回收线程核心线程用 take 永久阻塞保持存活;非核心用 poll 超时,超时后 timedOut 为 true 可能触发回收

七、整体执行流程

execute(task)
    │
    ├─ 线程数 < corePoolSize ──→ addWorker(task, true) ──→ 新建核心线程执行
    │
    ├─ 线程数 ≥ corePoolSize
    │       │
    │       ├─ workQueue.offer(task) 成功 ──→ 任务入队
    │       │       │
    │       │       └─ workerCount == 0 ──→ addWorker(null, false) 补一个空 Worker
    │       │
    │       └─ 队列满 ──→ addWorker(task, false) ──→ 新建非核心线程执行
    │               │
    │               └─ 失败 ──→ reject(task)
    │
    └─ Worker 启动 ──→ runWorker()
            │
            ├─ 执行 firstTask
            │
            └─ 循环 getTask()
                    │
                    ├─ take() / poll() 取到任务 ──→ task.run()
                    │
                    └─ 返回 null(超时或池关闭)──→ processWorkerExit()

八、状态与 ctl

// ctl = 高3位状态 + 低29位线程数
RUNNING    = -1 << 29   // 接受新任务、处理队列
SHUTDOWN   =  0 << 29   // 不再接受新任务,继续处理队列
STOP       =  1 << 29   // 不再接受新任务,不处理队列,中断正在执行的任务
TIDYING    =  2 << 29   // 所有任务已结束,workerCount=0
TERMINATED =  3 << 29   // terminated() 已执行

九、小结

环节作用
execute()决定:新建核心线程 / 入队 / 新建非核心线程 / 拒绝
addWorker()创建 Worker、加入 workers、启动线程
Worker封装线程和 firstTask,实现 Runnable
runWorker()循环取任务并执行,退出时调用 processWorkerExit
getTask()从队列取任务,控制超时回收和池关闭时的退出