为什么不用 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。
-
FixedThreadPool
- 特点:线程数量固定,核心线程数 = 最大线程数。
- 队列:无界队列
LinkedBlockingQueue。 - 适用:CPU密集型任务,如复杂的图片处理、计算等,能有效避免线程频繁切换的开销-1。
-
CachedThreadPool
- 特点:核心线程数为0,最大线程数非常大,空闲线程存活60秒。
- 队列:同步队列
SynchronousQueue(不存储任务,必须立刻执行)。 - 适用:大量、短时、I/O密集型任务,如网络请求、文件读写。任务量大时会疯狂创建线程,需谨慎使用。
-
SingleThreadExecutor
- 特点:只有一个线程,核心和最大线程数均为1。
- 队列:无界队列
LinkedBlockingQueue。 - 适用:需要保证所有任务按顺序执行的场景,如单线程的数据库操作或文件写入。
-
ScheduledThreadPool
重要提示:在阿里巴巴Java开发手册等规范中,不推荐直接使用
Executors创建线程池。因为FixedThreadPool和SingleThreadPool使用的无界队列可能导致OOM,而CachedThreadPool允许创建大量线程也可能导致OOM。建议通过ThreadPoolExecutor构造函数显式指定参数-1。
📋 任务队列
任务队列(BlockingQueue)用于存放等待执行的任务,是线程池的关键组件-2-7。
- 无界队列 (
LinkedBlockingQueue): 容量为Integer.MAX_VALUE,可无限添加任务,但风险极高,任务堆积会耗尽内存。FixedThreadPool使用了它-1。 - 有界队列 (
ArrayBlockingQueue): 需指定固定容量,强制限流,队列满后才尝试创建非核心线程,是更安全的选择。 - 同步移交队列 (
SynchronousQueue): 容量为0,不存任务,必须立刻有线程接手,否则就创建新线程。CachedThreadPool使用了它。 - 延迟工作队列 (
DelayedWorkQueue): 按延迟时间排序,时间最短的优先出队。ScheduledThreadPool使用它来实现延迟和周期执行-7。