以下是对 Kotlin launch 从入口到 Android 线程调度的完整源码级分析,逐层深入到 kotlinx.coroutines 核心实现。
一、入口层:launch 函数
launch 定义在 Builders.common.kt 中,是 CoroutineScope 的扩展函数:
kotlin
// kotlinx.coroutines.Builders.common.kt
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
// 1. 合并上下文
val newContext = newCoroutineContext(context)
// 2. 根据启动模式创建协程体
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block)
else
StandaloneCoroutine(newContext, active = true)
// 3. 启动协程
coroutine.start(start, coroutine, block)
// 4. 返回 Job,外部可通过它取消或等待
return coroutine
}
关键洞察 :launch 只干三件事------合上下文、造协程体、启动它。
二、上下文合并:newCoroutineContext
kotlin
// kotlinx.coroutines.CoroutineContext.common.kt
public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {
// 父 Scope 的 context + 传入的 context,后者覆盖前者同 key 的元素
val combined = coroutineContext + context
// DEBUG 模式下追加唯一 ID,便于日志追踪
val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined
// 如果没有指定 Dispatcher,默认追加 Dispatchers.Default
return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)
debug + Dispatchers.Default
else
debug
}
上下文合并规则:
-
coroutineContext + context:右侧覆盖左侧同 key 的元素(如传入Dispatchers.Main会覆盖 Scope 默认的Dispatchers.IO)。 -
ContinuationInterceptorkey 用于存储 Dispatcher,若未设置则默认Dispatchers.Default。
三、协程体创建:StandaloneCoroutine
kotlin
// kotlinx.coroutines.Builders.common.kt
private open class StandaloneCoroutine(
parentContext: CoroutineContext,
active: Boolean
) : AbstractCoroutine<Unit>(parentContext, initParentJob = true, active = active)
继承链:
plain
StandaloneCoroutine
→ AbstractCoroutine<Unit>
→ JobSupport ← 实现 Job 的完整状态机(Active/Completing/Cancelled)
→ Continuation<Unit> ← 实现 Continuation 接口,作为协程完成的回调
StandaloneCoroutine 同时是 Job (生命周期管理)和 Continuation(恢复回调)。
对于 LAZY 模式,创建的是 LazyStandaloneCoroutine,初始状态为 EMPTY_NEW(非活跃),只有调用 start()/join() 时才会触发执行。
四、启动分发:CoroutineStart
coroutine.start(start, coroutine, block) 最终会调用 CoroutineStart 的操作符重载:
kotlin
// kotlinx.coroutines.CoroutineStart
public operator fun <R, T> invoke(
block: suspend R.() -> T,
receiver: R,
completion: Continuation<T>
): Unit = when (this) {
DEFAULT -> block.startCoroutineCancellable(receiver, completion)
ATOMIC -> block.startCoroutine(receiver, completion)
UNDISPATCHED-> block.startCoroutineUndispatched(receiver, completion)
LAZY -> Unit // will start lazily
}
表格
| 模式 | 行为 |
|----------------|-------------------------------------|---|
| DEFAULT | 最常用 ,可响应取消,通过 Dispatcher 调度执行 |
| ATOMIC | 不可取消地启动,直到第一个挂起点才检查取消 |
| UNDISPATCHED | 直接在当前线程执行到第一个挂起点,不经过 Dispatcher |
| LAZY | 延迟启动,需手动触发 | |
五、核心:startCoroutineCancellable
这是 launch 源码中最关键的一行,也是协程真正"起飞"的地方:
kotlin
// kotlinx.coroutines.intrinsics.Cancellable.kt
public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit =
runSafely(completion) {
createCoroutineUnintercepted(completion)
.intercepted()
.resumeCancellableWith(Result.success(Unit))
}
拆解为三步:
5.1 createCoroutineUnintercepted
编译器会为 suspend { ... } lambda 生成一个继承 SuspendLambda 的匿名类。此方法调用该类的 create() 工厂方法,new 出状态机实例。
kotlin
// 编译器生成的伪代码
class MainActivity$onCreate$1 extends SuspendLambda {
int label; // 状态机标签
Object invokeSuspend(Object $result) {
switch (this.label) {
case 0:
this.label = 1;
if (job1(this) == COROUTINE_SUSPENDED)
return COROUTINE_SUSPENDED; // 挂起,等待恢复
case 1:
this.label = 2;
if (job2(this) == COROUTINE_SUSPENDED)
return COROUTINE_SUSPENDED;
case 2:
return Unit.INSTANCE;
}
}
}
CPS 变换本质 :Kotlin 编译器将 suspend 函数编译为状态机 ,通过 label 控制执行流程,每个挂起点对应一个状态。
5.2 .intercepted()
kotlin
// kotlin.coroutines.ContinuationInterceptor
public actual fun <T> Continuation<T>.intercepted(): Continuation<T> =
(this as? DispatchedContinuation<T>) ?: run {
val dispatcher = context[ContinuationInterceptor] as ContinuationInterceptor
dispatcher.interceptContinuation(this)
}
-
从
CoroutineContext中取出ContinuationInterceptor(即Dispatcher)。 -
用
DispatchedContinuation包装原始Continuation。 -
此后每次
resume都会经过 Dispatcher 分发到对应线程。
5.3 .resumeCancellableWith()
kotlin
// kotlinx.coroutines.DispatchedContinuation
public fun resumeCancellableWith(result: Result<T>) {
val dispatcher = delegate.context[ContinuationInterceptor]!!
// 通过 Dispatcher 将恢复任务投递到目标线程
dispatcher.dispatch(context, DispatchTask(this, result))
}
同时包装了取消检测 :在任务执行前检查 Job.isActive,若已取消则直接走取消流程,不执行业务代码。
六、Android 主线程调度:Dispatchers.Main
在 Android 平台,Dispatchers.Main 的实现是 HandlerContext:
kotlin
// kotlinx.coroutines.android.HandlerDispatcher.kt
internal class HandlerContext(
private val handler: Handler,
private val name: String? = null
) : HandlerDispatcher(), Delay {
override fun dispatch(context: CoroutineContext, block: Runnable) {
// 通过 Handler.post 将协程任务投递到主线程 Looper
handler.post(block)
}
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
// delay 的实现:Handler.postDelayed
handler.postDelayed(
Runnable { continuation.resumeUndispatched(Unit) },
timeMillis
)
}
}
执行链路:
plain
resumeCancellableWith()
→ HandlerContext.dispatch()
→ handler.post(Runnable { continuation.resumeWith(result) })
→ 主线程 Looper 取出消息
→ BaseContinuationImpl.resumeWith()
→ invokeSuspend() 继续执行状态机
Dispatchers.Main.immediate 会额外检查 Looper.myLooper() == Looper.getMainLooper(),若已在主线程则直接执行,避免一帧延迟。
七、挂起与恢复的完整链路
挂起(Suspend)
kotlin
// 以 delay 为例
public suspend fun delay(timeMillis: Long) {
if (timeMillis <= 0) return
return suspendCancellableCoroutine { cont: CancellableContinuation<Unit> ->
// 注册一个定时器,时间到后调用 cont.resume()
scheduleResumeAfterDelay(timeMillis, cont)
}
}
suspendCancellableCoroutine 会:
-
将当前
Continuation挂起。 -
返回
COROUTINE_SUSPENDED。 -
invokeSuspend()收到COROUTINE_SUSPENDED后直接返回,当前线程被释放。
恢复(Resume)
定时器到期 / IO 完成 / 用户点击
↓
CancellableContinuation.resume(Unit)
↓
DispatchedContinuation.resumeWith(Result.success(Unit))
↓
Dispatcher.dispatch(context, task) ← 决定恢复线程
↓
线程执行任务
↓
BaseContinuationImpl.resumeWith(result)
↓
invokeSuspend() 根据 label 跳转到对应状态继续执行
八、结构化并发:父子 Job 的绑定
StandaloneCoroutine 的父 Job 来自 CoroutineScope 的上下文。在 AbstractCoroutine 初始化时:
kotlin
// kotlinx.coroutines.JobSupport
init {
if (initParentJob) {
// 将当前协程作为子 Job 注册到父 Job
parentContext[Job]?.attachChild(this)
}
}
这意味着:
-
父
Jobcancel → 所有子协程收到取消信号。 -
子协程异常 → 向上传播,父协程 cancel,兄弟协程连带取消(除非使用
SupervisorJob)。
九、完整调用链总结图
用户代码: lifecycleScope.launch(Dispatchers.IO) { ... }
│
▼
┌─────────────────────────────────────┐
│ launch(context, start=DEFAULT, block)│ ← Builders.common.kt
│ val newContext = newCoroutineContext │
│ → combined = scope.context + IO │
│ → + Dispatchers.Default (若未指定) │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ StandaloneCoroutine(newContext) │ ← 继承 AbstractCoroutine/JobSupport
│ initParentJob = true → 绑定父 Job │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ coroutine.start(DEFAULT, self, block)│
│ → block.startCoroutineCancellable │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ createCoroutineUnintercepted() │ ← 编译器生成 SuspendLambda
│ .intercepted() │ ← IO Dispatcher 包装
│ .resumeCancellableWith(Unit) │ ← 提交到 IO 线程池
└─────────────────────────────────────┘
│
▼
IO 线程执行 block
│
遇到 delay/withContext/suspend 函数
│
返回 COROUTINE_SUSPENDED
│
线程释放,回到线程池
│
时间到 / 回调触发
│
Dispatcher.dispatch → IO 线程
│
resumeWith() → invokeSuspend()
│
状态机 label++,继续执行
│
withContext(Main) → Handler.post → 主线程
│
更新 UI ...
│
执行完毕 → StandaloneCoroutine 进入 Completed 状态
│
通知父 Job → 子 Job 完成
十、关键源码文件索引
| 功能 | 文件路径 |
|---|---|
launch / async / runBlocking |
kotlinx.coroutines.Builders.common.kt |
| 上下文合并 | kotlinx.coroutines.CoroutineContext.common.kt |
Job 状态机 |
kotlinx.coroutines.JobSupport.kt |
| 可取消启动 | kotlinx.coroutines.intrinsics.Cancellable.kt |
Continuation.intercepted() |
kotlin.coroutines.jvm.internal.ContinuationImpl.kt |
| Android 主线程调度 | kotlinx.coroutines.android.HandlerDispatcher.kt |
Dispatchers.Default/IO |
kotlinx.coroutines.scheduling.DefaultScheduler.kt |