协程基础与挂起本质
协程 (Coroutines) 是一种基于线程之上的 用户态轻量级线程。 它的核心优势在于:以顺序写法的代码,实现非阻塞的异步逻辑。
什么是“轻量级”?
你可以轻松创建 10 万个协程,但这在线程世界是不可想象的(会 OOM)。 协程不绑定到特定线程,它可以在一个线程挂起,并在另一个线程恢复。
kotlin
// 启动 10 万个协程,仅占用极少内存
repeat(100_000) {
launch {
delay(1000L)
print(".")
}
}挂起函数 (Suspend Function)
suspend 关键字是协程魔法的开关。
- 非阻塞挂起: 当协程遇到
delay或其他挂起函数时,它会释放当前占用的线程(线程去干别的事了),直到挂起结束。 - 自动恢复: 挂起结束后,协程会被调度器重新分配线程继续执行。
kotlin
suspend fun fetchDoc() {
// 挂起点 1: 释放主线程,网络请求在 IO 线程跑
val data = networkRequest()
// 自动切回:继续执行
show(data)
}协程构建器
只有构建器(Builder)才能从普通世界跨入协程世界。
kotlin
// "Fire-and-Forget" (发射即不管)
// 返回 Job,无返回结果
scope.launch {
// 异步逻辑
}kotlin
// "Future-style" (有结果)
// 返回 Deferred<T>,需调用 await() 获取结果
val deferred = scope.async {
calculate()
}
val result = deferred.await()kotlin
// 阻塞当前线程直到内部逻辑执行完
// ⚠️ 仅用于 main() 函数。严禁在 UI 线程使用!
// 对于单元测试,请优先使用专用的 [runTest](/kotlin/coroutines-testing)。
runBlocking {
delay(1000)
}结构化并发 (Structured Concurrency)
Kotlin 协程不鼓励“野生”协程。所有协程必须依附于一个 作用域 (CoroutineScope)。
- 父子关系: 在父协程中启动的子协程,自动建立层级关系。
- 同生共死: 父作用域取消,所有子协程自动取消。
- 责任闭环: 父协程必须等待所有子协程执行完毕,自己才能完成。
kotlin
// 自定义作用域逻辑
suspend fun loadUI() = coroutineScope { // 创建一个子作用域
launch { loadPart1() }
launch { loadPart2() }
// 只有当 part1 和 part2 都结束,loadUI 函数才会返回
}scope 构建器对比
coroutineScope: 一个失败,全家爆炸。任何子协程抛出异常,整个作用域取消。supervisorScope: 各自安好。子协程失败不会影响兄弟协程。
kotlin
supervisorScope {
launch { throw Error() } // 炸了
launch { delay(100); print("I am alive") } // 依然活着 ✅
}