一句话总结:
用餐厅厨房类比理解:
AsyncTask的线程池就像餐厅的后厨系统:
- 厨师(线程) :处理订单(任务)
- 传菜口(Handler) :把做好的菜(结果)送回前厅(主线程)
- 排班表(线程池配置) :决定有多少厨师同时工作
一、AsyncTask线程池核心配置
1. 双线程池结构
// 源码关键参数(Android 11之前)
private static final int CORE_POOL_SIZE = 1; // 核心线程数
private static final int MAXIMUM_POOL_SIZE = 20; // 最大线程数
private static final int KEEP_ALIVE_SECONDS = 3; // 空闲线程存活时间
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE,
KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(128), // 任务队列容量
sThreadFactory
);
参数解读:
- 核心厨师:至少保持1个线程存活
- 最大厨师数:最多可扩容到20个线程
- 临时工存活:空闲3秒后回收多余线程
- 订单队列:最多堆积128个待处理任务
2. 版本行为差异
| Android版本 | 默认执行模式 | 特性说明 |
|---|---|---|
| ≤ 1.5(Cupcake) | 并行执行 | 多个任务同时处理 |
| 1.6(Donut)~ 2.3(Gingerbread) | 串行执行 | 任务排队逐个处理 |
| ≥ 3.0(Honeycomb) | 可控模式 | 可通过executeOnExecutor()自定义 |
二、任务调度流程
1. 默认串行模式流程
// 实际执行顺序控制
val SERIAL_EXECUTOR = object : Executor {
private val mTasks = ArrayDeque<Runnable>()
private var mActive: Runnable? = null
override fun execute(r: Runnable) {
mTasks.offer(Runnable {
try {
r.run()
} finally {
scheduleNext()
}
})
if (mActive == null) scheduleNext()
}
}
工作流程:
- 新任务加入队列尾部
- 当前任务完成后触发下一个
- 保证任务顺序执行
2. 并行模式启动方式
// 使用原生线程池实现并行
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
// 自定义线程池示例
val customExecutor = ThreadPoolExecutor(
4, // 核心线程
10, // 最大线程
5, TimeUnit.SECONDS,
LinkedBlockingQueue(100)
)
task.executeOnExecutor(customExecutor)
三、线程池工作示意图
新任务到达 → 核心线程是否空闲?
├─ 是 → 立即执行
└─ 否 → 进入等待队列?
├─ 队列未满 → 加入队列
└─ 队列已满 → 创建新线程(不超过MAXIMUM_POOL_SIZE)
├─ 成功 → 执行任务
└─ 失败 → 触发拒绝策略
四、实际开发中的坑与解决方案
坑1:任务堆积导致ANR
错误现象:
- 大量短任务快速提交导致队列阻塞
优化方案:
// 监控队列负载
val executor = AsyncTask.THREAD_POOL_EXECUTOR as ThreadPoolExecutor
if (executor.queue.size > 50) {
// 触发降级策略
}
坑2:内存泄漏
危险代码:
class MyActivity : Activity() {
fun doTask() {
// 匿名内部类隐式持有Activity引用
object : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void): Void {
// 长时间运行任务
return null
}
}.execute()
}
}
正确方案:
// 使用弱引用 + 静态内部类
class SafeTask(activity: MyActivity) : AsyncTask<Void, Void, Void>() {
private val weakRef = WeakReference(activity)
override fun doInBackground(vararg params: Void): Void {
weakRef.get()?.apply {
// 操作前检查是否存活
}
return null
}
}
五、替代方案推荐
| 场景 | 推荐方案 | 优势 |
|---|---|---|
| 简单后台任务 | Kotlin协程 | 轻量级、结构化并发 |
| 长时间运行 | WorkManager | 生命周期感知、省电优化 |
| 即时UI更新 | Handler + Executor | 精细控制线程切换 |
| 复杂数据流 | RxJava | 强大的操作符支持 |
AsyncTask线程池使用口诀:
核心线程打头阵,队列满了才扩容
串行就像单车道,并行车道可多开
存活时间要合理,避免资源太浪费
内存泄漏是大敌,弱引用保平安!