目录
- 协程基础概念
- 协程核心机制
- 协程与线程对比
- 协程调度原理
- 挂起函数工作原理
- 结构化并发与生命周期
- 异步流处理(Flow)
- 最佳实践与性能优化
- 高级主题:状态机与Continuation
- 实战场景与常见问题
1. 协程基础概念
1.1 什么是协程
- 轻量级并发单元(用户态线程)
- Kotlin官方推荐的异步编程解决方案
- 核心特性:挂起/恢复、结构化并发、非阻塞
- 本质:基于状态机与回调的高级抽象
1.2 核心组件
组件 | 作用 | 示例 |
---|---|---|
挂起函数 | 支持暂停/恢复的函数 | suspend fun fetchData(): Data |
协程构建器 | 创建协程的方式 | launch{} , async{} , runBlocking{} |
调度器 | 控制协程执行线程 | Dispatchers.Main , Dispatchers.IO |
作用域 | 管理协程生命周期 | CoroutineScope , viewModelScope |
2. 协程核心机制
2.1 挂起与恢复
- 挂起(Suspend):协程暂停执行,释放线程资源
- 恢复(Resume):在条件满足时继续执行
- 关键对象 :
Continuation
保存协程状态
kotlin
// 挂起点示例
suspend fun loadData() {
val data = fetchFromNetwork() // 挂起点
process(data) // 恢复后执行
}
2.2 非阻塞原理
阶段 | 协程状态 | 线程状态 |
---|---|---|
执行耗时操作前 | 运行中 | 执行任务 |
进入IO操作点 | →挂起 | →立即释放 |
后台处理中 | 挂起中 | 执行其他任务 |
操作完成 | →恢复 | →重新调度执行 |
3. 协程与线程对比
3.1 核心差异
特性 | 协程 | Java线程 |
---|---|---|
资源开销 | ~100字节/协程 | ~1MB/线程 |
创建数量 | 单线程数万协程 | 数千线程耗尽资源 |
切换机制 | 用户态切换(≈10ns) | 内核态切换(≈1μs) |
阻塞行为 | 挂起释放线程 | 阻塞整个线程 |
取消机制 | 结构化一键取消 | 手动interrupt+检查 |
调度控制 | 精确Dispatcher控制 | 依赖OS调度 |
3.2 性能对比
kotlin
// 创建1000个"任务"执行1秒延迟
// 协程版
fun coroutinesTest() = runBlocking {
repeat(1000) {
launch(Dispatchers.Default) { delay(1000) }
}
} // 耗时: ~1s, 内存: <10MB
// 线程版
fun threadsTest() {
repeat(1000) {
Thread { Thread.sleep(1000) }.start()
}
} // 耗时: >3s, 内存: >100MB
4. 协程调度原理
4.1 Dispatchers类型
调度器 | 线程池特性 | 适用场景 |
---|---|---|
Main |
UI线程 | Android UI更新 |
IO |
64线程+缓存 | 网络/文件IO |
Default |
CPU核心数线程 | 计算密集型 |
Unconfined |
不限制 | 特殊调试场景 |
4.2 调度流程

5. 挂起函数工作原理
5.1 挂起函数执行流程
- 调用
suspend
函数传递隐式Continuation
- 执行到挂起点(如网络请求)返回
COROUTINE_SUSPENDED
- 注册回调保留
Continuation
- IO操作完成后调用
continuation.resume(result)
- 协程重新进入调度队列
5.2 回调转挂起
kotlin
// 传统回调转挂起函数
suspend fun loadData(): String = suspendCancellableCoroutine { cont ->
retrofitService.fetchData().enqueue(object : Callback {
override fun onSuccess(data: String) {
cont.resume(data)
}
override fun onFailure(e: Exception) {
cont.resumeWithException(e)
}
})
// 回调前可取消
cont.invokeOnCancellation {
retrofitService.cancel()
}
}
6. 结构化并发与生命周期
6.1 结构化并发三原则
- 作用域绑定:协程必须属于特定作用域
- 父子关系:子协程继承父协程上下文
- 取消传播:父协程取消时自动取消子协程
6.2 Android生命周期管理
kotlin
class MyViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch {
// 子协程自动管理
val data = withContext(Dispatchers.IO) {
repository.loadData()
}
updateUI(data)
}
// ViewModel销毁时自动取消所有协程
}
}
7. 异步流处理(Flow)
7.1 Flow核心概念
特性 | 说明 | 对比RxJava |
---|---|---|
冷流 | 无订阅者不触发 | 类似Observable |
背压支持 | 默认同步处理 | 需特殊操作符 |
操作符链 | 声明式数据处理 | 类似操作符 |
线程切换 | flowOn 控制 |
subscribeOn |
7.2 基本使用
kotlin
fun getDataStream(): Flow<Data> = flow {
emit(loadFromCache())
emit(loadFromNetwork())
}
// 收集流
viewModelScope.launch {
getDataStream()
.map { it.toViewData() }
.flowOn(Dispatchers.IO)
.catch { e -> emit(ErrorData(e)) }
.collect { updateUI(it) }
}
7.3 StateFlow & SharedFlow
kotlin
// 状态管理
private val _uiState = MutableStateFlow<UiState>(Loading)
val uiState: StateFlow<UiState> = _uiState
// 事件总线
private val _events = MutableSharedFlow<Event>()
val events = _events.asSharedFlow()
// 发送更新
fun updateData() {
viewModelScope.launch {
_uiState.value = Loading
val data = repository.loadData()
_uiState.value = Success(data)
_events.emit(ShowToast("Updated"))
}
}
8. 最佳实践与性能优化
8.1 最佳实践原则
-
DIspatcher显式指定
kotlinsuspend fun loadData() = withContext(Dispatchers.IO) { // IO操作 }
-
避免全局作用域
kotlin// ❌ 避免 GlobalScope.launch { /* ... */ } // ✅ 推荐 viewModelScope.launch { /* ... */ }
-
合理使用async/await
kotlinval user = async { getUser() } val posts = async { getPosts() } updateUI(user.await(), posts.await())
8.2 性能优化技巧
-
减少Dispatcher切换
kotlinwithContext(Dispatchers.Default) { val data = withContext(Dispatchers.IO) { loadData() } processData(data) // 同线程执行 }
-
协程选择策略
场景 推荐方案 单次请求 launch + withContext
并行任务 async/await
流式数据 Flow
状态管理 StateFlow
9. 高级主题:状态机与Continuation
9.1 状态机转换
java
// 源码:
suspend fun fetchData(): String {
val data = requestNetwork()
return process(data)
}
// 伪代码转换结果:
class FetchDataContinuation(
var state: Int,
var result: Any?
) : Continuation {
fun invokeSuspend(result: Result<Any?>) {
when (state) {
0 -> {
state = 1
requestNetwork(this) // 注册回调
}
1 -> {
val data = result as String
state = 2
process(data, this)
}
2 -> return result
}
}
}
9.2 Continuation核心方法
kotlin
interface Continuation<in T> {
// 协程执行上下文
val context: CoroutineContext
// 恢复协程执行
fun resumeWith(result: Result<T>)
}
// 恢复扩展函数
fun <T> Continuation<T>.resume(value: T) {
resumeWith(Result.success(value))
}
10. 实战场景与常见问题
10.1 典型应用场景
-
网络请求
kotlinviewModelScope.launch { try { val data = withContext(Dispatchers.IO) { retrofitService.getData() } _state.value = UiState.Success(data) } catch (e: Exception) { _state.value = UiState.Error(e) } }
-
数据库监听
kotlin@Dao interface UserDao { @Query("SELECT * FROM users") fun getUsers(): Flow<List<User>> }
-
多数据源合并
kotlinval userData = flow { emit(repo.getUser()) } val newsData = flow { emit(repo.getNews()) } userData.combine(newsData) { user, news -> ProfileData(user, news) }.collect { updateUI(it) }
10.2 常见问题解答
Q: 协程会在后台线程阻塞吗?
A: 不会。只要使用正确的Dispatcher:
Dispatchers.IO
适合阻塞IO操作Dispatchers.Default
适合CPU密集型任务
Q: 如何避免取消导致资源泄露?
kotlin
suspend fun doTask() {
withContext(Dispatchers.IO) {
val resource = openResource()
try {
// 检查取消状态
ensureActive()
useResource(resource)
} finally {
// 确保资源释放
resource.close()
}
}
}
Q: 如何处理并行异常?
kotlin
viewModelScope.launch {
val deferred1 = async { task1() }
val deferred2 = async { task2() }
try {
val results = awaitAll(deferred1, deferred2)
} catch (e: Exception) {
// 处理任一任务异常
}
}
附录:协程调试技巧
-
添加协程名称
kotlinlaunch(CoroutineName("NetworkRequest")) { ... }
-
启用调试模式
kotlin// build.gradle kotlin { jvmToolchain(11) compilerOptions.freeCompilerArgs.add( "-Xdebug" ) }
-
异常堆栈跟踪
kotlin// 获取当前协程信息 fun currentCoroutineInfo() = "Coroutine ${coroutineContext[CoroutineName]}"
结语
Kotlin协程通过创新的挂起机制和结构化并发模型,为现代异步编程提供了强大的解决方案。本文档全面覆盖了从基础概念到底层实现的各个方面,帮助开发者:
- 深入理解协程工作原理
- 避免常见并发陷阱
- 构建高性能异步应用
- 充分利用Kotlin语言特性