浅谈ThreadPool

Android 线程池(ThreadPool)架构与使用详解


一、整体架构总览

css 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        Executor 框架体系                          │
│                                                                 │
│  ┌───────────────┐                                              │
│  │   Executor     │  ← 顶层接口: execute(Runnable)               │
│  └───────┬───────┘                                              │
│          │                                                      │
│  ┌───────▼───────────┐                                          │
│  │ ExecutorService    │  ← 扩展: submit/shutdown/invokeAll       │
│  └───────┬───────────┘                                          │
│          │                                                      │
│  ┌───────▼─────────────────┐                                    │
│  │ AbstractExecutorService  │  ← 模板方法实现                     │
│  └───────┬─────────────────┘                                    │
│          │                                                      │
│  ┌───────▼─────────────────┐    ┌───────────────────────┐       │
│  │  ThreadPoolExecutor     │    │ ScheduledThreadPool    │       │
│  │  (核心实现)              │    │ Executor (定时任务)     │       │
│  └───────┬─────────────────┘    └───────────────────────┘       │
│          │                                                      │
│          │  工厂类封装                                            │
│  ┌───────▼─────────────────────────────────────────────┐        │
│  │                   Executors (工厂类)                  │        │
│  │  ├── newFixedThreadPool()                           │        │
│  │  ├── newCachedThreadPool()                          │        │
│  │  ├── newSingleThreadExecutor()                      │        │
│  │  ├── newScheduledThreadPool()                       │        │
│  │  └── newWorkStealingPool() (Java 8, ForkJoinPool)   │        │
│  └─────────────────────────────────────────────────────┘        │
│                                                                 │
│  Android 特有 / 框架使用                                          │
│  ┌─────────────────────────────────────────────────────┐        │
│  │  AsyncTask.THREAD_POOL_EXECUTOR (已废弃)             │        │
│  │  Glide: GlideExecutor (多个专用线程池)                │        │
│  │  OkHttp: Dispatcher 内部线程池                       │        │
│  │  Room: 查询/写入线程池                                │        │
│  │  Kotlin Coroutines: Dispatchers.Default/IO           │        │
│  │  WorkManager: Configuration.executor                 │        │
│  └─────────────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────────────┘

二、ThreadPoolExecutor 核心架构

构造函数 --- 7 个关键参数

java 复制代码
public ThreadPoolExecutor(
    int corePoolSize,         // 核心线程数(常驻)
    int maximumPoolSize,      // 最大线程数
    long keepAliveTime,       // 非核心线程空闲存活时间
    TimeUnit unit,            // 时间单位
    BlockingQueue<Runnable> workQueue,   // 任务等待队列
    ThreadFactory threadFactory,         // 线程工厂
    RejectedExecutionHandler handler     // 拒绝策略
)
ini 复制代码
┌────────────────────────────────────────────────────────────────┐
│                   ThreadPoolExecutor 内部结构                    │
│                                                                │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                    Worker 线程集合                         │  │
│  │                                                          │  │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐     ┌─────────┐   │  │
│  │  │ Worker-1 │ │ Worker-2 │ │ Worker-3 │ ... │ Worker-N │   │  │
│  │  │ (核心)   │ │ (核心)   │ │ (非核心)  │     │ (非核心)  │   │  │
│  │  └────┬────┘ └────┬────┘ └────┬────┘     └────┬────┘   │  │
│  │       │           │           │               │         │  │
│  │       └───────────┴─────┬─────┴───────────────┘         │  │
│  │                         │ 竞争获取任务                     │  │
│  │                         ▼                                │  │
│  │              ┌─────────────────────┐                     │  │
│  │              │  BlockingQueue       │                     │  │
│  │              │  (任务等待队列)        │                     │  │
│  │              │  ┌───┬───┬───┬───┐  │                     │  │
│  │              │  │T5 │T6 │T7 │T8 │  │                     │  │
│  │              │  └───┴───┴───┴───┘  │                     │  │
│  │              └─────────────────────┘                     │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                │
│  corePoolSize = 3                                              │
│  maximumPoolSize = 5                                           │
│  keepAliveTime = 60s                                           │
│  workQueue = LinkedBlockingQueue(128)                          │
│                                                                │
│  ctl (AtomicInteger): 高3位=状态, 低29位=线程数                   │
│  状态: RUNNING → SHUTDOWN → STOP → TIDYING → TERMINATED        │
└────────────────────────────────────────────────────────────────┘

任务提交流程 --- 最核心的逻辑

scss 复制代码
execute(Runnable task)
    │
    ▼
┌───────────────────────────────────┐
│ 当前线程数 < corePoolSize ?        │
│                                   │
│  YES → 创建核心线程执行任务          │ ──→ 直接运行
│                                   │
│  NO ↓                             │
└───────────────────┬───────────────┘
                    │
                    ▼
┌───────────────────────────────────┐
│ workQueue.offer(task) 入队成功?    │
│                                   │
│  YES → 任务入队等待               │ ──→ 排队等待空闲线程
│        (再次检查线程池状态)          │
│                                   │
│  NO ↓ (队列满)                    │
└───────────────────┬───────────────┘
                    │
                    ▼
┌───────────────────────────────────┐
│ 当前线程数 < maximumPoolSize ?     │
│                                   │
│  YES → 创建非核心线程执行任务       │ ──→ 紧急线程处理
│                                   │
│  NO ↓ (已达最大线程数)             │
└───────────────────┬───────────────┘
                    │
                    ▼
┌───────────────────────────────────┐
│ 执行拒绝策略                       │
│ RejectedExecutionHandler.reject() │
└───────────────────────────────────┘

用具体数字举例(core=3, max=5, queue=128)

makefile 复制代码
任务1-3到来: 创建核心线程 1,2,3 分别执行       → 线程数: 3
任务4-131到来: 进入队列排队 (队列容量128)       → 队列: 128个任务
任务132到来: 队列满, 创建非核心线程4 执行        → 线程数: 4
任务133到来: 创建非核心线程5 执行               → 线程数: 5
任务134到来: 线程数=max, 队列满 → 触发拒绝策略   → 抛异常/丢弃/...

Worker 线程工作循环

java 复制代码
// 简化的 Worker.run() 逻辑
final void runWorker(Worker w) {
    Runnable task = w.firstTask;  // 创建时分配的第一个任务
    w.firstTask = null;

    while (task != null || (task = getTask()) != null) {
        // 加锁
        w.lock();
        try {
            beforeExecute(thread, task);  // 钩子方法
            task.run();                    // 执行任务!
            afterExecute(task, null);      // 钩子方法
        } finally {
            task = null;
            w.completedTasks++;
            w.unlock();
        }
    }
    // getTask() 返回 null → 线程退出
    processWorkerExit(w, completedAbruptly);
}

// getTask(): 从队列获取任务
private Runnable getTask() {
    for (;;) {
        boolean timed = (当前线程数 > corePoolSize) || allowCoreThreadTimeOut;

        Runnable r = timed
            ? workQueue.poll(keepAliveTime, unit)  // 超时获取 → 超时返回null → 线程销毁
            : workQueue.take();                     // 阻塞获取 → 核心线程永远等待

        if (r != null) return r;
        // 超时且线程数>core → 返回null → 线程退出循环 → 销毁
    }
}
css 复制代码
线程生命周期:

核心线程:
  创建 → 执行任务 → 队列空 → take()阻塞等待 → 新任务来 → 执行 → ... (永远循环)

非核心线程:
  创建 → 执行任务 → 队列空 → poll(60s)等待 → 超时 → 返回null → 线程销毁
                                           → 有任务 → 执行 → ...

三、阻塞队列详解

scss 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    BlockingQueue 选择                             │
├──────────────────┬────────────┬──────────────────────────────────┤
│      类型         │   容量      │           特点                    │
├──────────────────┼────────────┼──────────────────────────────────┤
│ LinkedBlockingQueue│ 可选/无界   │ 链表实现,吞吐量高                  │
│                  │ (默认MAX)   │ ⚠️无界时max参数无效,可能OOM        │
├──────────────────┼────────────┼──────────────────────────────────┤
│ ArrayBlockingQueue │ 有界(必选)  │ 数组实现,公平/非公平锁可选          │
│                  │            │ 有界→可触发创建非核心线程             │
├──────────────────┼────────────┼──────────────────────────────────┤
│ SynchronousQueue  │ 0 (不存储)  │ 直接交接,不缓冲任务                 │
│                  │            │ 每个任务必须有线程接收               │
│                  │            │ CachedThreadPool 使用             │
├──────────────────┼────────────┼──────────────────────────────────┤
│ PriorityBlocking  │ 无界       │ 按优先级排序                       │
│ Queue            │            │ 需实现 Comparable                  │
├──────────────────┼────────────┼──────────────────────────────────┤
│ DelayQueue        │ 无界       │ 延迟获取                          │
│                  │            │ ScheduledThreadPool 底层使用       │
└──────────────────┴────────────┴──────────────────────────────────┘

队列选择对线程池行为的决定性影响

lua 复制代码
SynchronousQueue (容量=0):
  任务来 → 无法入队 → 必须创建线程 → 线程数快速增长到 max
  适合: 大量短任务, CachedThreadPool

ArrayBlockingQueue (有界):
  任务来 → 入队 → 队列满 → 创建非核心线程 → 线程数达max → 拒绝
  适合: 控制资源使用, 生产环境推荐

LinkedBlockingQueue (无界):
  任务来 → 永远能入队 → 非核心线程永远不会创建 → max参数失效
  适合: 固定线程数场景, FixedThreadPool
  ⚠️ 风险: 任务积压导致 OOM

四、四种拒绝策略

java 复制代码
// 当线程数 = max 且队列满时触发

┌────────────────────┬────────────────────────────────────────┐
│       策略          │              行为                       │
├────────────────────┼────────────────────────────────────────┤
│ AbortPolicy        │ 抛出 RejectedExecutionException        │
│ (默认)             │ 调用方感知到失败                          │
├────────────────────┼────────────────────────────────────────┤
│ CallerRunsPolicy   │ 由提交任务的线程自己执行                   │
│                    │ 不丢弃任务,但会阻塞调用方                  │
│                    │ 形成天然的反压(back-pressure)             │
├────────────────────┼────────────────────────────────────────┤
│ DiscardPolicy      │ 静默丢弃新提交的任务                      │
│                    │ 无任何通知 (危险)                        │
├────────────────────┼────────────────────────────────────────┤
│ DiscardOldestPolicy│ 丢弃队列中最老的任务,然后重新提交新任务      │
│                    │ 适合只关心最新数据的场景                   │
└────────────────────┴────────────────────────────────────────┘
java 复制代码
// 自定义拒绝策略 (Android 推荐做法)
RejectedExecutionHandler handler = (runnable, executor) -> {
    // 方案1: 记录日志 + 降级
    Log.e("ThreadPool", "任务被拒绝: " + runnable.toString());
    reportToMonitor(runnable);

    // 方案2: 放入备用队列
    backupQueue.offer(runnable);

    // 方案3: 在新线程中执行 (保证执行但不受池管理)
    if (!executor.isShutdown()) {
        new Thread(runnable, "backup-thread").start();
    }
};

五、Executors 工厂类 --- 四种预设线程池

1. FixedThreadPool(固定大小)

java 复制代码
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(
        nThreads,                          // core = max
        nThreads,                          // 固定线程数
        0L, TimeUnit.MILLISECONDS,         // 不超时(核心线程不销毁)
        new LinkedBlockingQueue<Runnable>() // ⚠️ 无界队列
    );
}
ini 复制代码
┌──────────────────────────────────────────────────┐
│  FixedThreadPool(4)                               │
│                                                  │
│  线程: [T1] [T2] [T3] [T4]   ← 始终4个           │
│                  ↑                               │
│  队列: [任务5][任务6][任务7]... ← 无界,永远排队      │
│                                                  │
│  特点: 线程数固定,任务排队                           │
│  优点: 资源可控,适合CPU密集型                        │
│  缺点: 无界队列,任务积压可能OOM                      │
│  适用: 已知并发量的后台任务                           │
└──────────────────────────────────────────────────┘

2. CachedThreadPool(弹性大小)

java 复制代码
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(
        0,                                 // core = 0
        Integer.MAX_VALUE,                 // max = 无上限
        60L, TimeUnit.SECONDS,             // 空闲60s销毁
        new SynchronousQueue<Runnable>()   // 不缓冲,直接交接
    );
}
ini 复制代码
┌──────────────────────────────────────────────────┐
│  CachedThreadPool                                │
│                                                  │
│  初始: 无线程                                     │
│  任务来: 无空闲线程 → 创建新线程                     │
│  任务来: 有空闲线程 → 复用                          │
│  空闲60s: 线程销毁                                │
│                                                  │
│  时刻1: [T1忙] [T2忙] [T3忙]                      │
│  时刻2: [T1忙] [T2闲] [T3闲] [T4忙]               │
│  时刻3: [T1忙] [T2销毁] [T3销毁] [T4闲]            │
│                                                  │
│  特点: 来多少任务开多少线程                          │
│  优点: 弹性伸缩,短任务响应快                         │
│  缺点: ⚠️ 并发量大时线程数爆炸,OOM                  │
│  适用: 大量短生命周期任务 (OkHttp Dispatcher)        │
└──────────────────────────────────────────────────┘

3. SingleThreadExecutor(单线程)

java 复制代码
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService(
        new ThreadPoolExecutor(
            1, 1,                              // 只有1个线程
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>() // 无界队列
        )
    );
}
ini 复制代码
┌──────────────────────────────────────────────────┐
│  SingleThreadExecutor                            │
│                                                  │
│  线程: [T1]  ← 始终1个                            │
│          ↑                                       │
│  队列: [任务2][任务3][任务4]... ← 严格串行执行       │
│                                                  │
│  特点: 所有任务串行执行,保证顺序                     │
│  优点: 无并发问题,天然线程安全                       │
│  缺点: 吞吐量低                                   │
│  适用: 数据库写入/日志写入/顺序事件处理               │
└──────────────────────────────────────────────────┘

4. ScheduledThreadPool(定时/周期)

java 复制代码
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(
        corePoolSize,                       // 核心线程数
        Integer.MAX_VALUE,                  // max 无上限
        // 内部使用 DelayedWorkQueue (基于堆的优先队列)
    );
}
java 复制代码
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

// 延迟执行
scheduler.schedule(() -> {
    Log.d("Task", "3秒后执行");
}, 3, TimeUnit.SECONDS);

// 固定频率执行 (不考虑任务耗时)
scheduler.scheduleAtFixedRate(() -> {
    Log.d("Task", "每5秒执行");
}, 0, 5, TimeUnit.SECONDS);
// |--任务--|        |--任务--|        |--任务--|
// 0s      2s       5s      7s       10s

// 固定延迟执行 (上次结束后等待固定时间)
scheduler.scheduleWithFixedDelay(() -> {
    Log.d("Task", "执行完后等3秒再执行");
}, 0, 3, TimeUnit.SECONDS);
// |--任务--|   3s   |--任务--|   3s   |--任务--|
// 0s      2s       5s      7s       10s

对比总结

scss 复制代码
┌────────────────────┬────────┬──────────┬──────────┬──────────────┐
│                    │ core   │   max    │  队列     │    适用场景    │
├────────────────────┼────────┼──────────┼──────────┼──────────────┤
│ Fixed(N)           │  N     │   N      │ 无界链表  │ CPU密集型     │
│ Cached             │  0     │  MAX     │ 同步队列  │ 大量短I/O任务  │
│ Single             │  1     │   1      │ 无界链表  │ 串行任务      │
│ Scheduled(N)       │  N     │  MAX     │ 延迟队列  │ 定时/周期任务  │
└────────────────────┴────────┴──────────┴──────────┴──────────────┘

⚠️ 阿里编码规范: 禁止使用 Executors 创建线程池
   原因: FixedThreadPool/SingleThreadExecutor 无界队列→OOM
         CachedThreadPool 无限线程→OOM
   推荐: 手动 new ThreadPoolExecutor(), 明确参数

六、Android 中的实际线程池应用

1. AsyncTask 线程池(已废弃,了解设计)

java 复制代码
// Android 源码中的线程池定义
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;

public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
    CORE_POOL_SIZE,                        // 2~4
    MAXIMUM_POOL_SIZE,                     // CPU*2+1
    KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
    new LinkedBlockingQueue<Runnable>(128), // 有界! 128
    sThreadFactory
);

// 设计解读:
// core = CPU-1 (留一个核给主线程)
// max = CPU*2+1 (考虑I/O等待时可多开)
// 队列128 (有界, 防止OOM)

2. OkHttp Dispatcher 线程池

java 复制代码
// OkHttp 内部
public synchronized ExecutorService executorService() {
    if (executorService == null) {
        executorService = new ThreadPoolExecutor(
            0,                                  // core = 0
            Integer.MAX_VALUE,                  // max = 无限
            60, TimeUnit.SECONDS,               // 60s 回收
            new SynchronousQueue<>(),            // 同步队列
            Util.threadFactory("OkHttp Dispatcher", false)
        );
    }
    return executorService;
}

// 但! OkHttp 在 Dispatcher 层面做了并发控制:
//   maxRequests = 64
//   maxRequestsPerHost = 5
// 所以实际不会创建无限线程

3. Glide 线程池

java 复制代码
// Glide 的多线程池策略
public final class GlideExecutor {

    // 磁盘缓存线程池 (1个线程, 避免磁盘竞争)
    public static GlideExecutor newDiskCacheExecutor() {
        return new ThreadPoolExecutor(
            1, 1, 0, MILLISECONDS,
            new PriorityBlockingQueue<>(),
            new DefaultThreadFactory("glide-disk-cache")
        );
    }

    // 网络/源数据加载线程池
    public static GlideExecutor newSourceExecutor() {
        int bestThreadCount = calculateBestThreadCount(); // 基于CPU核心数
        return new ThreadPoolExecutor(
            bestThreadCount, bestThreadCount,
            0, MILLISECONDS,
            new PriorityBlockingQueue<>(),
            new DefaultThreadFactory("glide-source")
        );
    }

    // 动画线程池 (GIF 解码)
    public static GlideExecutor newAnimationExecutor() {
        int bestThreadCount = calculateBestAnimationThreadCount(); // 1-2
        return new ThreadPoolExecutor(
            bestThreadCount, bestThreadCount, 0, MILLISECONDS,
            new PriorityBlockingQueue<>(),
            new DefaultThreadFactory("glide-animation")
        );
    }
}

4. Kotlin Coroutines Dispatchers

kotlin 复制代码
// Dispatchers.Default  → CPU 密集型
//   底层: 共享的 CoroutineScheduler
//   线程数: max(2, CPU核心数)
//   有工作窃取算法

// Dispatchers.IO → I/O 密集型
//   底层: 与 Default 共享 CoroutineScheduler
//   线程数: max(64, CPU核心数)
//   额外的线程专门用于阻塞I/O

// Dispatchers.Main ��� 主线程
//   底层: Handler(Looper.getMainLooper())

// Dispatchers.Unconfined → 不限制
//   在调用方线程启动, 在第一个挂起点后在恢复它的线程继续

// 关系图:
//  ┌───────────────────────────────────────────┐
//  │          CoroutineScheduler                │
//  │  ┌──────────────────────────────────────┐ │
//  │  │  Worker 线程池 (共享)                  │ │
//  │  │  ┌──┐ ┌──┐ ┌──┐ ... ┌──┐            │ │
//  │  │  │W1│ │W2│ │W3│     │Wn│            │ │
//  │  │  └──┘ └──┘ └──┘     └──┘            │ │
//  │  └──────────────────────────────────────┘ │
//  │       ↑ Default 使用           ↑ IO 额外线程│
//  │       (CPU核心数个)          (最多64个)     │
//  └───────────────────────────────────────────┘

七、Android 最佳实践 --- 手动创建线程池

1. 全局线程池管理器

java 复制代码
public class AppExecutors {

    private static volatile AppExecutors instance;

    // CPU 密集型任务 (计算/解码/排序)
    private final ExecutorService cpuExecutor;

    // I/O 密集型任务 (网络/数据库/文件)
    private final ExecutorService ioExecutor;

    // 单线程串行 (数据库写入/日志)
    private final ExecutorService singleExecutor;

    // 定时任务
    private final ScheduledExecutorService scheduledExecutor;

    // 主线程
    private final Executor mainExecutor;

    private AppExecutors() {
        int cpuCount = Runtime.getRuntime().availableProcessors();

        // CPU 密集型: 核心数+1 (多1个防止某线程偶尔阻塞)
        cpuExecutor = new ThreadPoolExecutor(
            cpuCount + 1,
            cpuCount + 1,
            30, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(128),
            new NamedThreadFactory("cpu"),
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝时调用方执行
        );

        // I/O 密集型: 核心数 * 2 (I/O等待时可让出CPU)
        ioExecutor = new ThreadPoolExecutor(
            cpuCount * 2,
            cpuCount * 2 + 1,
            30, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(256),    // 有界队列!
            new NamedThreadFactory("io"),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );

        // 串行任务
        singleExecutor = new ThreadPoolExecutor(
            1, 1,
            0, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(64),
            new NamedThreadFactory("single"),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );

        // 定时任务
        scheduledExecutor = new ScheduledThreadPoolExecutor(
            2,
            new NamedThreadFactory("scheduled")
        );

        // 主线程
        mainExecutor = new MainThreadExecutor();
    }

    public static AppExecutors getInstance() {
        if (instance == null) {
            synchronized (AppExecutors.class) {
                if (instance == null) {
                    instance = new AppExecutors();
                }
            }
        }
        return instance;
    }

    public ExecutorService cpu() { return cpuExecutor; }
    public ExecutorService io() { return ioExecutor; }
    public ExecutorService single() { return singleExecutor; }
    public ScheduledExecutorService scheduled() { return scheduledExecutor; }
    public Executor main() { return mainExecutor; }

    // 主线程 Executor
    private static class MainThreadExecutor implements Executor {
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(Runnable command) {
            handler.post(command);
        }
    }

    // 自定义线程工厂 (命名 + 优先级 + 异常处理)
    private static class NamedThreadFactory implements ThreadFactory {
        private final AtomicInteger counter = new AtomicInteger(0);
        private final String prefix;

        NamedThreadFactory(String prefix) {
            this.prefix = prefix;
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "app-" + prefix + "-" + counter.getAndIncrement());
            t.setDaemon(false);
            // Android: 设置线程优先级
            t.setPriority(Thread.NORM_PRIORITY);
            // 未捕获异常处理
            t.setUncaughtExceptionHandler((thread, throwable) -> {
                Log.e("ThreadPool", "线程异常: " + thread.getName(), throwable);
                // 上报崩溃
                CrashReporter.report(throwable);
            });
            return t;
        }
    }

    // 关闭 (Application.onTerminate 或不需要时)
    public void shutdown() {
        cpuExecutor.shutdown();
        ioExecutor.shutdown();
        singleExecutor.shutdown();
        scheduledExecutor.shutdown();
    }
}

2. 使用示例

java 复制代码
// I/O 任务: 网络请求
AppExecutors.getInstance().io().execute(() -> {
    String result = apiService.fetchData();

    // 切回主线程更新 UI
    AppExecutors.getInstance().main().execute(() -> {
        textView.setText(result);
    });
});

// CPU 密集型: 图片处理
AppExecutors.getInstance().cpu().execute(() -> {
    Bitmap processed = heavyImageProcessing(bitmap);

    AppExecutors.getInstance().main().execute(() -> {
        imageView.setImageBitmap(processed);
    });
});

// 串行任务: 数据库写入
AppExecutors.getInstance().single().execute(() -> {
    database.insert(record1);
    database.insert(record2); // 保证顺序
});

// 定时任务: 心跳
AppExecutors.getInstance().scheduled().scheduleAtFixedRate(() -> {
    sendHeartbeat();
}, 0, 30, TimeUnit.SECONDS);

// 带返回值的任务
Future<String> future = AppExecutors.getInstance().io().submit(() -> {
    return apiService.fetchData();
});
String result = future.get(5, TimeUnit.SECONDS); // 阻塞等待结果

八、线程数量设计原则

ini 复制代码
┌─────────────────────────────────────────────────────────────┐
│                  线程数计算公式                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  CPU 密集型任务 (计算/解码/压缩):                              │
│    线程数 = CPU 核心数 + 1                                   │
│    理由: 多1个防止偶尔的页面错误/I/O阻塞浪费CPU                 │
│                                                             │
│  I/O 密集型任务 (网络/数据库/文件):                             │
│    线程数 = CPU 核心数 × 2                                   │
│    理由: I/O等待时CPU空闲,可以切换到其他线程                     │
│                                                             │
│  更精确的公式 (《Java并发编程实战》):                           │
│    N_threads = N_cpu × U_cpu × (1 + W/C)                   │
│    N_cpu = CPU核心数                                        │
│    U_cpu = 目标CPU使用率 (0~1)                               │
│    W/C   = 等待时间 / 计算时间                                │
│                                                             │
│  示例 (4核, 目标80%利用率, I/O等待是计算的4倍):                 │
│    N = 4 × 0.8 × (1 + 4) = 16 个线程                       │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│  Android 特殊考虑:                                           │
│  - 移动设备 CPU 核心通常 4-8 个                               │
│  - 大小核架构 (4大核+4小核)                                   │
│  - 电量敏感: 线程过多→CPU频繁唤醒→耗电                         │
│  - 内存有限: 每个线程栈约 1MB                                  │
│  - 建议总线程数控制在 20-30 以内                               │
└─────────────────────────────────────────────────────────────┘

九、submit vs execute

java 复制代码
// execute: 无返回值, 异常直接抛出
executor.execute(() -> {
    throw new RuntimeException("crash!");
    // → UncaughtExceptionHandler 捕获
    // → 线程死亡, 线程池创建新线程替代
});

// submit: 有返回值(Future), 异常被封装
Future<?> future = executor.submit(() -> {
    throw new RuntimeException("crash!");
    // → 异常不会立即抛出!
    // → 线程不会死亡
});

try {
    future.get(); // 这里才抛出 ExecutionException
} catch (ExecutionException e) {
    Throwable cause = e.getCause(); // 获取原始异常
}
scss 复制代码
┌────────────┬────────────────┬──────────────────────────────┐
│            │   execute()    │          submit()             │
├────────────┼────────────────┼──────────────────────────────┤
│ 返回值      │ void           │ Future<T>                    │
│ 异常处理    │ 直接抛出到线程   │ 封装在 Future 中              │
│            │ UncaughtHandler│ get() 时才抛出                │
│ 线程存活    │ 异常→线程死亡   │ 异常→线程存活继续复用           │
│ 适用场景    │ fire-and-forget│ 需要结果/需要感知异常           │
└────────────┴────────────────┴──────────────────────────────┘

⚠️ submit 的坑: 如果不调用 future.get(), 异常被静默吞掉!
解决方案:
java 复制代码
// 方案1: 包装 Runnable, 捕获异常
executor.submit(() -> {
    try {
        riskyOperation();
    } catch (Exception e) {
        Log.e("Pool", "任务异常", e);
        // 上报
    }
});

// 方案2: 重写 afterExecute 钩子
ThreadPoolExecutor pool = new ThreadPoolExecutor(...) {
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t == null && r instanceof Future<?>) {
            try {
                ((Future<?>) r).get();
            } catch (ExecutionException e) {
                t = e.getCause();
            } catch (Exception e) {
                t = e;
            }
        }
        if (t != null) {
            Log.e("Pool", "任务执行异常", t);
        }
    }
};

十、线程池监控

关键指标

java 复制代码
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

// 实时状态
int activeCount     = pool.getActiveCount();      // 正在执行任务的线程数
int poolSize        = pool.getPoolSize();          // 当前线程总数
int queueSize       = pool.getQueue().size();      // 队列中等待的任务数
long completedCount = pool.getCompletedTaskCount(); // 已完成任务总数
long taskCount      = pool.getTaskCount();          // 提交的任务总数
int largestPoolSize = pool.getLargestPoolSize();    // 历史最大线程数

Log.d("Pool", String.format(
    "active=%d, pool=%d, queue=%d, completed=%d, largest=%d",
    activeCount, poolSize, queueSize, completedCount, largestPoolSize
));

定时监控

java 复制代码
// 定期输出线程池状态
ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor();
monitor.scheduleAtFixedRate(() -> {
    ThreadPoolExecutor pool = (ThreadPoolExecutor) AppExecutors.getInstance().io();

    int queueSize = pool.getQueue().size();
    int activeCount = pool.getActiveCount();

    // 预警: 队列积压
    if (queueSize > 100) {
        Log.w("PoolMonitor", "⚠️ IO线程池队列积压: " + queueSize);
        reportMetric("thread_pool_queue_backlog", queueSize);
    }

    // 预警: 线程数异常
    if (pool.getPoolSize() > pool.getCorePoolSize() * 2) {
        Log.w("PoolMonitor", "⚠️ 线程数异常增长: " + pool.getPoolSize());
    }

    // 定期上报
    reportMetric("thread_pool_active", activeCount);
    reportMetric("thread_pool_queue", queueSize);
    reportMetric("thread_pool_size", pool.getPoolSize());

}, 0, 10, TimeUnit.SECONDS);

自定义可监控线程池

java 复制代码
public class MonitoredThreadPoolExecutor extends ThreadPoolExecutor {

    private final String name;
    private final ConcurrentHashMap<Runnable, Long> startTimes = new ConcurrentHashMap<>();

    public MonitoredThreadPoolExecutor(String name, int core, int max,
            long keepAlive, TimeUnit unit, BlockingQueue<Runnable> queue) {
        super(core, max, keepAlive, unit, queue, new NamedThreadFactory(name));
        this.name = name;
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        startTimes.put(r, System.nanoTime());

        // 设置 Android 线程优先级
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);

        Long startTime = startTimes.remove(r);
        if (startTime != null) {
            long elapsed = (System.nanoTime() - startTime) / 1_000_000;
            if (elapsed > 1000) { // 超过1秒
                Log.w("Pool-" + name, "慢任务: " + elapsed + "ms, task=" + r);
            }
        }

        // 异常处理
        if (t != null) {
            Log.e("Pool-" + name, "任务异常", t);
        }
    }

    @Override
    protected void terminated() {
        super.terminated();
        Log.i("Pool-" + name, "线程池已终止");
    }
}

十一、线程池关闭

java 复制代码
// shutdown(): 温和关闭
executor.shutdown();
// → 不再接受新任务
// → 已提交的任务(队列中+执行中)继续执行
// → 所有任务完成后线程池终止

// shutdownNow(): 强制关闭
List<Runnable> pending = executor.shutdownNow();
// → 不再接受新任务
// → 尝试中断所有执行中的线程 (interrupt)
// → 返回队列中未执行的任务
// → 不保证执行中的任务能停止

// 推荐的关闭方式 (优雅关闭)
public void gracefulShutdown(ExecutorService executor, int timeoutSec) {
    executor.shutdown(); // 先温和关闭

    try {
        // 等待已有任务完成
        if (!executor.awaitTermination(timeoutSec, TimeUnit.SECONDS)) {
            Log.w("Pool", "超时未完成, 强制关闭");
            executor.shutdownNow(); // 超时则强制

            // 再等一会
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                Log.e("Pool", "线程池未能终止!");
            }
        }
    } catch (InterruptedException e) {
        executor.shutdownNow();
        Thread.currentThread().interrupt();
    }
}

// Android 中的关闭时机
// Application.onTerminate() ← 模拟器才调用,不可靠
// 推荐: Activity/Service onDestroy 时关闭对应的线程池
// 或: 全局线程池随进程生命周期,不主动关闭

十二、常见陷阱与解决方案

陷阱 1:任务异常导致线程死亡

java 复制代码
// ❌ 问题: execute 中未捕获的异常会杀死线程
executor.execute(() -> {
    int result = 1 / 0; // ArithmeticException
    // → 线程死亡, 线程池创建新线程替代
    // → 频繁创建销毁,性能差
});

// ✅ 解决: 始终 try-catch
executor.execute(() -> {
    try {
        int result = 1 / 0;
    } catch (Exception e) {
        Log.e("Task", "任务执行失败", e);
    }
});

陷阱 2:线程池引用 Activity 导致内存泄漏

java 复制代码
// ❌ 问题: 匿名内部类持有外部 Activity 引用
public class MyActivity extends Activity {
    void loadData() {
        executor.execute(() -> {
            String data = fetchData();
            // 隐式持有 MyActivity.this
            runOnUiThread(() -> textView.setText(data)); // Activity 已销毁!
        });
    }
}

// ✅ 解决1: 弱引用
public class MyActivity extends Activity {
    void loadData() {
        WeakReference<MyActivity> weakRef = new WeakReference<>(this);
        executor.execute(() -> {
            String data = fetchData();
            MyActivity activity = weakRef.get();
            if (activity != null && !activity.isDestroyed()) {
                activity.runOnUiThread(() -> textView.setText(data));
            }
        });
    }
}

// ✅ 解决2: Lifecycle 感知 (推荐)
// 使用 Kotlin Coroutines + lifecycleScope
lifecycleScope.launch {
    val data = withContext(Dispatchers.IO) { fetchData() }
    textView.text = data  // 自动在 onDestroy 时取消
}

陷阱 3:线程池参数不当

java 复制代码
// ❌ core=0, max=大, 无界队列 → 只有1个线程工作
new ThreadPoolExecutor(0, 100, 60, SECONDS,
    new LinkedBlockingQueue<>()); // 无界队列
// core=0, 任务全部入队, 只创建1个线程消费队列
// max=100 永远触发不了!

// ❌ core=大, 有界队列小 → 频繁拒绝
new ThreadPoolExecutor(2, 2, 0, SECONDS,
    new ArrayBlockingQueue<>(1)); // 容量1
// 第4个任务就被拒绝!

// ✅ 合理配置
int cpu = Runtime.getRuntime().availableProcessors();
new ThreadPoolExecutor(
    cpu,              // core: CPU 核心数
    cpu * 2,          // max: 2倍
    30, SECONDS,      // 非核心线程30秒回收
    new ArrayBlockingQueue<>(256),      // 有界队列
    new CallerRunsPolicy()              // 满了就调用方执行
);

陷阱 4:多个线程池资源浪费

java 复制代码
// ❌ 每个模块各自创建线程池
class ModuleA { ExecutorService pool = Executors.newFixedThreadPool(4); }
class ModuleB { ExecutorService pool = Executors.newFixedThreadPool(4); }
class ModuleC { ExecutorService pool = Executors.newFixedThreadPool(4); }
// → 12个常驻线程, 内存浪费, 线程切换开销

// ✅ 全局统一管理 + 按类型区分
// 整个 App 只维护 2-3 个线程池 (CPU / IO / Single)
AppExecutors.getInstance().io().execute(...);
AppExecutors.getInstance().cpu().execute(...);

十三、与 Kotlin Coroutines 对比

kotlin 复制代码
// 传统线程池方式
AppExecutors.getInstance().io().execute {
    val data = api.fetchData()            // 后台线程
    AppExecutors.getInstance().main().execute {
        textView.text = data              // 主线程
    }
}

// Kotlin Coroutines 方式 (推荐)
lifecycleScope.launch {                   // 主线程开始
    val data = withContext(Dispatchers.IO) { // 自动切到IO线程
        api.fetchData()
    }
    textView.text = data                  // 自动切回主线程
}                                         // Activity销毁自动取消
vbnet 复制代码
┌──────────────────┬──────────────────┬──────────────────────┐
│                  │    线程池          │    Coroutines         │
├──────────────────┼──────────────────┼──────────────────────┤
│ 线程切换          │ 手动 post/execute │ withContext 自动切换   │
│ 取消             │ Future.cancel()  │ Job.cancel() / 自动    │
│ 生命周期感知      │ 需手动管理        │ lifecycleScope 自动    │
│ 异常处理          │ try-catch/回调    │ try-catch + Handler   │
│ 嵌套/组合         │ 回调地狱          │ 顺序代码风格           │
│ 并发控制          │ CountDownLatch   │ async/await           │
│ 底层实现          │ 直接管理线程      │ 基于线程池(Dispatchers) │
│ 学习成本          │ 低               │ 中                    │
│ 推荐程度          │ 仍然有效          │ ✅ Android 首选        │
└──────────────────┴──────────────────┴──────────────────────┘

Coroutines 底层仍然使用线程池:
  Dispatchers.Default → SharedPool (CPU核心数线程)
  Dispatchers.IO      → SharedPool (最多64线程)
  Dispatchers.Main    → Handler(MainLooper)

理解线程池是理解 Coroutines 的基础!

十四、完整架构图

scss 复制代码
┌─────────────────────────────────────────────────────────────┐
│                    Android App 线程架构                       │
│                                                             │
│  ┌─────────────┐                                           │
│  │  Main Thread │  ← UI 渲染 / 事件处理 / 生命周期            │
│  │  (UI Thread) │     Looper + MessageQueue + Handler       │
│  └──────┬──────┘                                           │
│         │ post / runOnUiThread                              │
│         │                                                   │
│  ┌──────▼──────────────────────────────────────────────┐   │
│  │              AppExecutors (全局线程池管理)              │   │
│  │                                                      │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌───────────┐  │   │
│  │  │  CPU Pool     │  │   IO Pool    │  │  Single   │  │   │
│  │  │  core=CPU+1   │  │  core=CPU×2  │  │  core=1   │  │   │
│  │  │  图片处理      │  │  网络/数据库   │  │  串行写入  │  │   │
│  │  │  JSON解析     │  │  文件读写     │  │  日志记录  │  │   │
│  │  │  数据计算      │  │  SP读写      │  │           │  │   │
│  │  └──────────────┘  └──────────────┘  └───────────┘  │   │
│  │                                                      │   │
│  │  ┌──────────────┐  ┌──────────────────────────────┐  │   │
│  │  │ Scheduled    │  │  Main Thread Executor         │  │   │
│  │  │  定时心跳     │  │  Handler(MainLooper).post()   │  │   │
│  │  │  轮询刷新     │  │  回调切回主线程                │  │   │
│  │  └──────────────┘  └──────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐   │
│  │            第三方框架自带线程池                          │   │
│  │  OkHttp Dispatcher  │  Glide Executors               │   │
│  │  Room QueryExecutor │  WorkManager                   │   │
│  │  Retrofit + RxJava  │  Coroutine Dispatchers          │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

总结

markdown 复制代码
ThreadPoolExecutor 核心要点:

1. 七参数理解
   core / max / keepAlive / queue / factory / handler
   → 它们共同决定了线程池的行为模式

2. 任务提交三步曲
   core未满→创建核心线程 → 队列未满→入队 → max未满→创建非核心线程 → 拒绝

3. 队列选择决定行为
   SynchronousQueue: 不缓冲,快速创建线程 (Cached)
   LinkedBlockingQueue: 无界,max失效 (Fixed/Single)
   ArrayBlockingQueue: 有界,推荐生产使用

4. Android 最佳实践
   - 全局 2-3 个线程池 (CPU/IO/Single)
   - 有界队列 + CallerRunsPolicy
   - 自定义 ThreadFactory (命名+优先级+异常处理)
   - 新项目首选 Kotlin Coroutines (底层仍是线程池)
相关推荐
帅次2 小时前
单例初始化中的耗时操作如何拖死主线程
android·webview·android runtime
kyriewen2 小时前
手写 Promise:从“我会用”到“我会造”
前端·javascript·面试
二十一_2 小时前
LangChain 教程 03|快速开始:10 分钟创建第一个 Agent
前端·面试·langchain
用户0874881999172 小时前
Android 资源类型全解析及四大常用布局资源深度指南
android
我叫黑大帅2 小时前
php 如何使用mysqli连接mysql
后端·面试·php
火锅鸡的味道2 小时前
解决AOSP工程Android Studio打开卡顿
android·python·android studio
我叫黑大帅3 小时前
PHP mysqli 实用开发指南
后端·面试·php
2501_915921433 小时前
2026 iOS 上架新趋势 iOS 发布流程模块化
android·ios·小程序·https·uni-app·iphone·webview
毕设源码-钟学长3 小时前
【开题答辩全过程】以 基于Android的高校二手交易系统为例,包含答辩的问题和答案
android