Java线程池 - 内部线程管理机制详解

线程池对线程的管理,核心在于 Worker 内部类ctl 状态控制变量。下面从创建、运行、销毁三个维度拆解。


一、Worker:线程池里的"线程包装器"

线程池并不直接持有 Thread 对象,而是包装成 Worker

复制代码
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
    final Thread thread;      // 真正干活的线程
    Runnable firstTask;       // 第一个任务(可能为 null)
    volatile long completedTasks;  // 已完成任务计数
    
    Worker(Runnable firstTask) {
        setState(-1);         // AQS 状态:-1 表示禁止中断,直到 runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);  // 创建线程
    }
    
    public void run() {
        runWorker(this);      // 线程启动后进入这里
    }
}

Worker 继承 AQS 的巧妙设计

Worker 继承 AbstractQueuedSynchronizer 不是为了排队,而是用 AQS 的状态来实现一个不可重入的互斥锁

状态 含义
-1 初始化中,禁止中断
0 未加锁(空闲)
1 已加锁(正在执行任务)

线程池通过 tryLock() 来判断 Worker 是否空闲,从而决定是否中断它。


二、线程创建:addWorker() 方法

当任务提交后,线程池判断需要创建新线程时,调用 addWorker()

复制代码
private boolean addWorker(Runnable firstTask, boolean core) {
    // 1. CAS 尝试增加线程计数(ctl 的低29位)
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);  // 获取运行状态
        
        // 状态检查:如果已 SHUTDOWN 且队列非空,不再创建
        if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
            return false;
            
        for (;;) {
            int wc = workerCountOf(c);  // 当前线程数
            // 容量检查:core 为 true 检查 corePoolSize,否则检查 maximumPoolSize
            if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))  // CAS 增加线程计数
                break retry;
            c = ctl.get();
            if (runStateOf(c) != rs)
                continue retry;  // 状态变了,重试外层循环
        }
    }
    
    // 2. 真正创建 Worker 并启动线程
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);      // 创建 Worker(内部创建 Thread)
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // 再次检查状态,将 Worker 加入 workers HashSet
                workers.add(w);
                workerAdded = true;
            } finally {
                mainLock.lock();
            }
            if (workerAdded) {
                t.start();              // 🚀 启动线程!
                workerStarted = true;
            }
        }
    } finally {
        if (!workerStarted)
            addWorkerFailed(w);         // 启动失败,回滚
    }
    return workerStarted;
}

创建流程图

复制代码
任务提交
   ↓
判断需要创建线程
   ↓
CAS 增加 ctl 线程计数(原子操作)
   ↓
new Worker(firstTask) → ThreadFactory.newThread(this)
   ↓
加 mainLock → workers.add(w)
   ↓
thread.start() → 执行 Worker.run() → runWorker(this)

三、线程运行:runWorker() 方法

线程启动后进入 runWorker(),这是线程的核心生命周期循环

复制代码
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock();  // 允许中断(state 从 -1 变为 0)
    
    boolean completedAbruptly = true;
    try {
        // 🔥 核心循环:先执行 firstTask,然后不断从队列取任务
        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++;
                w.unlock();  // 解锁,标记为"空闲"
            }
        }
        completedAbruptly = false;  // 正常退出循环
    } finally {
        processWorkerExit(w, completedAbruptly);  // 线程退出处理
    }
}

关键点

  • while 循环 :线程不会执行完一个任务就死,而是循环取任务,实现线程复用

  • getTask():从队列阻塞获取任务,这是线程"保活"或"销毁"的分水岭

  • w.lock()/unlock() :通过 AQS 锁标识线程是否在工作,便于 shutdown() 时区分"空闲线程"和"忙碌线程"


四、线程销毁:核心在 getTask()processWorkerExit()

4.1 getTask():决定线程是等待还是销毁

复制代码
private Runnable getTask() {
    boolean timedOut = false;
    
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        
        // 1. 线程池状态检查:STOP / SHUTDOWN 且队列为空 → 返回 null,线程销毁
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();  // 线程计数 -1
            return null;
        }
        
        int wc = workerCountOf(c);
        
        // 2. 判断是否需要超时回收
        // allowCoreThreadTimeOut 默认为 false
        // 如果线程数 > corePoolSize,或者允许核心线程超时,则 timed = true
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        
        // 3. 回收条件:
        //    (wc > maximumPoolSize 或 超时) 且 (wc > 1 或 队列为空)
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;  // 返回 null → 线程即将销毁
            continue;
        }
        
        try {
            // 4. 从队列取任务
            // timed = true  → poll(keepAliveTime)  带超时阻塞
            // timed = false → take()               无限阻塞
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
                
            if (r != null)
                return r;
            timedOut = true;   // 超时了,下次循环可能触发回收
        } catch (InterruptedException retry) {
            timedOut = false;  // 被中断,重试
        }
    }
}

销毁逻辑图解

复制代码
runWorker 循环
   ↓
getTask()
   ├── 线程池 STOP / (SHUTDOWN 且队列为空)
   │      └── return null → processWorkerExit() → 线程销毁
   │
   ├── 线程数 > corePoolSize(或 allowCoreThreadTimeOut=true)
   │      └── workQueue.poll(keepAliveTime) 
   │            ├── 超时未取到 → return null → 销毁
   │            └── 取到任务 → 继续执行
   │
   └── 线程数 ≤ corePoolSize(默认)
          └── workQueue.take() → 无限阻塞等待 → 线程保活

4.2 processWorkerExit():线程退出清理

复制代码
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // 1. 如果是异常退出,线程计数需要补减
    if (completedAbruptly)
        decrementWorkerCount();
    
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        completedTaskCount += w.completedTasks;  // 累加完成的任务数
        workers.remove(w);                        // 从 workers 集合移除
    } finally {
        mainLock.unlock();
    }
    
    // 2. 尝试终止线程池(如果是 SHUTDOWN 且队列为空,或 STOP)
    tryTerminate();
    
    // 3. 如果线程池还在运行,且线程数 < corePoolSize,补充线程
    int c = ctl.get();
    if (runStateLessThan(c, STOP)) {
        if (!completedAbruptly) {  // 正常退出
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && !workQueue.isEmpty())
                min = 1;
            if (workerCountOf(c) >= min)
                return;  // 不需要补充
        }
        addWorker(null, false);  // 补充一个线程(不带任务,从队列取)
    }
}

五、核心线程 vs 非核心线程:本质区别

核心线程 非核心线程
创建时机 任务提交时,线程数 < corePoolSize 队列满时,线程数 < maximumPoolSize
保活机制 workQueue.take() 无限阻塞 workQueue.poll(keepAliveTime) 超时阻塞
回收条件 默认不回收(除非 allowCoreThreadTimeOut(true) 空闲超过 keepAliveTime 自动回收
本质 没有本质区别 ,都是 Worker 对象,只是回收策略不同

线程池内部没有"核心线程"和"非核心线程"的区分标记 ,纯粹是通过 wc > corePoolSize 这个判断来决定使用 take() 还是 poll()


六、ctl:一个变量控制所有状态

复制代码
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// ctl = 高3位(运行状态) + 低29位(线程数量)

private static final int COUNT_BITS = Integer.SIZE - 3;  // 29
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;  // 29位最大值

// 状态常量(高3位)
private static final int RUNNING    = -1 << COUNT_BITS;  // 111
private static final int SHUTDOWN   =  0 << COUNT_BITS;  // 000
private static final int STOP       =  1 << COUNT_BITS;  // 001
private static final int TIDYING    =  2 << COUNT_BITS;  // 010
private static final int TERMINATED =  3 << COUNT_BITS;  // 011
状态 说明
RUNNING 接收新任务,处理队列任务
SHUTDOWN 不接收新任务,但处理队列中剩余任务(调用 shutdown()
STOP 不接收新任务,不处理队列任务,中断正在执行的任务(调用 shutdownNow()
TIDYING 所有任务完成,线程数为 0,准备执行 terminated() 钩子
TERMINATED terminated() 执行完毕

七、总结:线程生命周期全景图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      线程池 ThreadPoolExecutor               │
├─────────────────────────────────────────────────────────────┤
│  任务提交                                                    │
│     ↓                                                        │
│  addWorker(firstTask, core)                                  │
│     ↓                                                        │
│  new Worker(firstTask) → ThreadFactory.newThread(this)       │
│     ↓                                                        │
│  thread.start()                                              │
│     ↓                                                        │
│  Worker.run() → runWorker(Worker)                              │
│     ↓                                                        │
│  ┌─────────────────────────────────────┐                     │
│  │  while (task != null || getTask() != null)                │
│  │     ↓                                                      │
│  │  w.lock() → task.run() → w.unlock()  ← 循环复用            │
│  │     ↓                                                      │
│  │  getTask() 返回 null → 退出循环                            │
│  └─────────────────────────────────────┘                     │
│     ↓                                                        │
│  processWorkerExit(Worker, completedAbruptly)                  │
│     ↓                                                        │
│  workers.remove(Worker) → 线程被 GC 回收                    │
└─────────────────────────────────────────────────────────────┘

高频追问

Q:shutdown() 后线程池里的线程去哪了?

调用 shutdown() 后状态变为 SHUTDOWN,不再接收新任务。线程池会中断所有空闲线程 (通过 interruptIdleWorkers(),利用 Worker 的 AQS 锁判断空闲),让它们从 getTask() 的阻塞中醒来。醒来的线程发现状态是 SHUTDOWN 且队列为空,就会 return null 退出。

Q:shutdownNow() 为什么能立即停止任务?

状态变为 STOP,然后中断所有线程(无论空闲还是忙碌),清空队列。正在执行的任务如果响应中断会立即退出,不响应中断的则继续执行直到完成。

Q:如何设置核心线程也超时回收?

复制代码
executor.allowCoreThreadTimeOut(true);

这样所有线程都用 poll(keepAliveTime) 取任务,超时后全部回收,线程池可以收缩到 0 个线程。

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui