1. 基本概念对比
特性 线程池 (ThreadPool) 协程 (Coroutine)
本质 Java线程管理机制 Kotlin轻量级并发框架
最小执行单元 线程(Thread) 协程(Coroutine)
创建开销 较高(需分配系统线程资源) 极低(用户态调度)
并发模型 基于线程的抢占式调度 基于协程的协作式调度
2. 核心差异详解
2.1 资源消耗
线程池:
每个线程占用1MB左右栈内存
线程切换涉及内核态/用户态转换
典型线程池大小限制在CPU核心数的2-3倍
协程:
协程栈只需几十到几百字节
完全在用户态调度,无系统调用开销
可轻松创建数万个并发协程
2.2 编程模型
// 线程池示例
val executor = Executors.newFixedThreadPool(4)
executor.execute {
val result = doBlockingWork()
runOnUiThread { updateUI(result) }
}
// 协程示例
CoroutineScope(Dispatchers.IO).launch {
val result = doSuspendWork() // 挂起函数
withContext(Dispatchers.Main) { updateUI(result) }
}
2.3 阻塞处理
线程池:
阻塞操作会占用线程资源
可能导致线程饥饿
协程:
挂起(suspend)而非阻塞
线程可被其他协程复用
3. Android开发中的关键区别
3.1 生命周期管理
// 线程池需要手动管理
val executor = Executors.newSingleThreadExecutor()
onDestroy() {
executor.shutdown()
}
// 协程自动绑定生命周期
lifecycleScope.launch {
// 自动随Activity销毁取消
}
3.2 异常处理
线程池:
需设置UncaughtExceptionHandler
异常可能导致线程终止
协程:
结构化并发保证异常传播
可使用CoroutineExceptionHandler
3.3 上下文切换
// 线程池需要回调切换
executor.execute {
val result = heavyWork()
handler.post { updateUI(result) }
}
// 协程优雅切换
launch(Dispatchers.Default) {
val result = cpuIntensiveWork()
withContext(Dispatchers.Main) { updateUI(result) }
}
适用场景建议
使用线程池当:
需要执行Java阻塞式API
处理CPU密集型计算任务
与现有Java线程库集成
使用协程当:
需要高效IO操作
管理复杂异步流程
需要与生命周期绑定
编写响应式UI代码
6. 最佳实践方案
混合使用模式
// 将线程池包装为协程Dispatcher
val threadPoolDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()
CoroutineScope(Dispatchers.Main).launch {
// 使用协程调度IO任务
val data = withContext(Dispatchers.IO) { fetchData() }
// 使用线程池处理CPU密集型任务
val result = withContext(threadPoolDispatcher) { processData(data) }
updateUI(result)
}
迁移策略
将回调式API改用suspend函数封装
逐步替换AsyncTask/Handler为协程
保留线程池处理计算密集型任务
使用协程Flow替代RxJava观察者
在Android现代开发中,协程已成为处理异步操作的首选方案,但合理利用线程池处理特定场景仍很重要。