跳到主要内容

线程池

问题

Android 中线程池的原理和使用方式有哪些?

答案

ThreadPoolExecutor 核心参数

val threadPool = ThreadPoolExecutor(
2, // corePoolSize:核心线程数
4, // maximumPoolSize:最大线程数
60L, // keepAliveTime:非核心线程闲置超时
TimeUnit.SECONDS, // 时间单位
LinkedBlockingQueue(100), // workQueue:任务队列
Executors.defaultThreadFactory(), // threadFactory
ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
)

任务执行流程

Executors 预定义线程池

类型核心/最大线程队列用途
newFixedThreadPool(n)n / n无界队列CPU 密集型
newCachedThreadPool()0 / MAXSynchronousQueueIO 密集型
newSingleThreadExecutor()1 / 1无界队列顺序执行
newScheduledThreadPool(n)n / MAXDelayQueue定时任务
不推荐直接使用 Executors

newFixedThreadPoolnewSingleThreadExecutor 使用无界队列,可能导致 OOM。newCachedThreadPool 最大线程数为 Integer.MAX_VALUE,可能创建过多线程。推荐直接使用 ThreadPoolExecutor 明确指定参数。

Android 中的线程池使用

// 推荐:使用协程替代线程池
class ImageProcessor(
private val dispatcher: CoroutineDispatcher = Dispatchers.Default
) {
suspend fun processImages(images: List<Bitmap>): List<Bitmap> =
withContext(dispatcher) {
images.map { image ->
async { applyFilter(image) }
}.awaitAll()
}
}

// 仍需要线程池的场景:Java 代码、SDK 内部
object AppExecutors {
val diskIO = Executors.newSingleThreadExecutor()
val networkIO = Executors.newFixedThreadPool(3)
val mainThread = MainThreadExecutor()

private class MainThreadExecutor : Executor {
private val handler = Handler(Looper.getMainLooper())
override fun execute(command: Runnable) {
handler.post(command)
}
}
}

拒绝策略

策略行为
AbortPolicy抛出 RejectedExecutionException(默认)
CallerRunsPolicy在调用者线程执行(降速)
DiscardPolicy静默丢弃
DiscardOldestPolicy丢弃队列头部最旧任务

常见面试问题

Q1: 核心线程数如何设置?

答案

  • CPU 密集型(计算、排序):核心线程数 = CPU 核心数 + 1
  • IO 密集型(网络、文件):核心线程数 = CPU 核心数 × 2

Android 中可通过 Runtime.getRuntime().availableProcessors() 获取 CPU 核心数。实际建议使用协程的 Dispatchers.Default(CPU 核心数)和 Dispatchers.IO(最多 64 个线程)。

Q2: AsyncTask 为什么被废弃?

答案

AsyncTask(API 30 废弃)的主要问题:

  1. 内存泄漏:内部类持有 Activity 引用
  2. 生命周期不感知:Activity 销毁后仍在执行,onPostExecute 更新已销毁的 UI
  3. 串行/并行混乱:API 11 后默认串行执行,与直觉不符
  4. 异常处理困难doInBackground 的异常难以传递

替代方案:Kotlin 协程 + viewModelScope / lifecycleScope

相关链接