线程池基础知识

8 阅读4分钟

为什么不用 new Thread() 而用线程池?

问题new Thread()线程池
线程数量无上限,容易超限崩溃固定数量,超额排队
线程复用用完即销毁,频繁创建开销大复用线程,性能好
生命周期管理Activity销毁后线程还在跑 → 内存泄漏可统一取消、控制并发
线程命名Thread-1、Thread-2... Debug分不清可自定义名称,便于排查问题## 一句话比喻

**new Thread() 就像每次干活都临时招人,招完就开除;线程池是养几个固定员工,活再多也是这4个人干,排队等着。

代码对比

// ❌ new Thread():4个问题全中
new Thread(() -> doTask()).start();

// ✅ 线程池:4个问题全解决
ThreadFactory factory = r -> new Thread(r, "MyBiz-Thread");
ExecutorService pool = Executors.newFixedThreadPool(4, factory);
pool.execute(() -> doTask());

Android的线程池(ThreadPoolExecutor)是管理并发任务的核心。当任务数超过负荷时,就需要拒绝策略来决定如何处理新任务;而Android也通过Executors工厂类提供了几种封装好的常见线程池;这一切都依赖于不同类型的任务队列

📜 拒绝策略

当线程池处于关闭状态,或任务队列已满且线程数已达最大时,会触发拒绝策略。Java提供了4种内置策略,你也可以根据需要自定义-4-7

拒绝策略 (Handler)行为描述适用场景
AbortPolicy直接抛出 RejectedExecutionException 异常,这是默认策略核心业务,必须明确处理任务被拒绝的情况。
DiscardPolicy静默丢弃新提交的任务,不抛异常,不通知。业务不敏感,允许部分任务丢失(如非关键日志上报)。
DiscardOldestPolicy丢弃任务队列头部(等待最久)的任务,然后重新提交当前任务。需要保证新任务被执行的场景,但可能导致旧任务丢失。
CallerRunsPolicy调用者线程(提交任务的线程,通常是主线程)中直接执行该任务。避免任务被丢弃,同时利用调用者线程的阻塞来减缓任务提交速度,实现负反馈调节。

🧰 封装好的常见线程池

为了避免配置繁琐,Android通过Executors类提供了几种标准线程池-2-3-10

  1. FixedThreadPool

    • 特点:线程数量固定,核心线程数 = 最大线程数。
    • 队列:无界队列 LinkedBlockingQueue
    • 适用CPU密集型任务,如复杂的图片处理、计算等,能有效避免线程频繁切换的开销-1
  2. CachedThreadPool

    • 特点:核心线程数为0,最大线程数非常大,空闲线程存活60秒。
    • 队列:同步队列 SynchronousQueue(不存储任务,必须立刻执行)。
    • 适用大量、短时、I/O密集型任务,如网络请求、文件读写。任务量大时会疯狂创建线程,需谨慎使用。
  3. SingleThreadExecutor

    • 特点:只有一个线程,核心和最大线程数均为1。
    • 队列:无界队列 LinkedBlockingQueue
    • 适用需要保证所有任务按顺序执行的场景,如单线程的数据库操作或文件写入。
  4. ScheduledThreadPool

    • 特点:核心线程数固定,最大线程数无限。
    • 队列:延迟工作队列 DelayedWorkQueue
    • 适用执行定时或周期性任务,如心跳检测、定时数据同步-2-7

重要提示:在阿里巴巴Java开发手册等规范中,不推荐直接使用Executors创建线程池。因为FixedThreadPoolSingleThreadPool使用的无界队列可能导致OOM,而CachedThreadPool允许创建大量线程也可能导致OOM。建议通过ThreadPoolExecutor构造函数显式指定参数-1

📋 任务队列

任务队列(BlockingQueue)用于存放等待执行的任务,是线程池的关键组件-2-7

  • 无界队列 (LinkedBlockingQueue): 容量为Integer.MAX_VALUE,可无限添加任务,但风险极高,任务堆积会耗尽内存。FixedThreadPool使用了它-1
  • 有界队列 (ArrayBlockingQueue): 需指定固定容量,强制限流,队列满后才尝试创建非核心线程,是更安全的选择。
  • 同步移交队列 (SynchronousQueue): 容量为0,不存任务,必须立刻有线程接手,否则就创建新线程。CachedThreadPool使用了它。
  • 延迟工作队列 (DelayedWorkQueue): 按延迟时间排序,时间最短的优先出队。ScheduledThreadPool使用它来实现延迟和周期执行-7