kotlin - 协程 launch 源码分析

kotlin - 协程 launch 源码分析

CoroutineScope(Dispatchers.Main).launch {}

1. launch 函数入口

launch 是 CoroutineScope 的扩展函数,定义在 kotlinx.coroutines 库中:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    // 组合新的上下文
    val newContext = newCoroutineContext(context)
    // 创建协程对象
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    // 启动协程
    coroutine.start(start, coroutine, block)
    return coroutine
}

2. 关键组件解析

2.1 newCoroutineContext 上下文创建

public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {
    // 组合当前scope的context和传入的context
    val combined = coroutineContext + context
    // 如果没有指定Dispatcher,则添加默认的Dispatchers.Default
    val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined
    return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)
        debug + Dispatchers.Default else debug
}

2.2 协程对象创建

根据启动模式创建不同类型的协程实例:

根据启动模式创建不同类型的协程实例:
StandaloneCoroutine: 默认立即启动的协程
LazyStandaloneCoroutine: 延迟启动的协程(当调用start或join时才启动)

private open class StandaloneCoroutine(
    parentContext: CoroutineContext,
    active: Boolean
) : AbstractCoroutine(parentContext, active) {
    override fun handleJobException(exception: Throwable): Boolean {
        handleCoroutineException(context, exception)
        return true
    }
}

3. 协程启动过程

coroutine.start() 调用链:

public fun start(start: CoroutineStart, receiver: R, block: suspend R.() -> Unit) {
    start(block, receiver, this)
}

CoroutineStart 是一个枚举类,定义了不同的启动方式:

public enum class CoroutineStart {
    DEFAULT,    // 立即调度执行
    LAZY,       // 延迟启动
    ATOMIC,     // 原子方式启动(不可取消)
    UNDISPATCHED // 立即在当前线程执行第一段代码
}

4. 协程执行流程

以 DEFAULT 启动模式为例:

internal operator fun invoke(block: suspend R.() -> T, receiver: R, completion: Continuation) {
    when (this) {
        DEFAULT -> {
            // 获取当前上下文的调度器
            val context = completion.context
            // 判断是否需要调度
            if (context[ContinuationInterceptor]?.isDispatchNeeded(context) == true) {
                // 通过调度器执行
                intercepted().dispatch(context, block, receiver, completion)
            } else {
                // 直接在当前线程执行
                withCoroutineContext(context, null) {
                    block.startCoroutineCancellable(receiver, completion)
                }
            }
        }
        // 其他模式处理...
    }
}

5. 协程的 Continuation 机制

startCoroutineCancellable 最终会调用到协程的创建和执行:

internal fun (suspend (R) -> T).startCoroutineCancellable(
    receiver: R,
    completion: Continuation
) = runSafely(completion) {
    // 创建 Continuation
    createCoroutineUnintercepted(receiver, completion)
        // 拦截处理(如添加调度器)
        .intercepted()
        // 开始执行
        .resumeCancellableWith(Result.success(Unit))
}

6. 协程调度流程

当协程被调度时:

​​​​​​​1、通过 ContinuationInterceptor (通常是 CoroutineDispatcher) 决定运行线程
2、调度器将任务放入对应线程的任务队列
3、线程从队列取出任务执行

public override fun dispatch(context: CoroutineContext, block: Runnable) {
    try {
        // 将任务派发到线程池执行
        executor.execute(wrapTask(block))
    } catch (e: RejectedExecutionException) {
        // 处理拒绝执行的情况
        uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), e)
    }
}

7. 协程取消机制

launch 返回的 Job 支持取消操作:

public final override fun cancel(cause: CancellationException?) {
    // 如果已经取消则直接返回
    if (!makeCancelling(cause)) return
    // 完成取消操作
    finishCancellation()
}

private fun makeCancelling(cause: Throwable?): Boolean {
    // 原子操作设置取消状态
    _state.updateAndGet { state ->
        if (state !is Active) return false // 已经完成或取消
        // 创建 CancelledContinuation
        val update = state.completeStateFinalUpdate(cause)
        if (update === COMPLETING_RETRY) return@updateAndGet state // 重试
        update
    }
    return true
}

8. 异常处理流程

协程内部的异常通过 Job 层级向上传播:

private fun handleJobException(exception: Throwable): Boolean {
    // 调用异常处理器
    handleCoroutineException(context, exception)
    return true
}

public fun handleCoroutineException(context: CoroutineContext, exception: Throwable) {
    // 尝试使用上下文中注册的异常处理器
    try {
        context[CoroutineExceptionHandler]?.handleException(context, exception)
            ?: Thread.currentThread().let { thread ->
                // 默认处理:打印到控制台
                thread.uncaughtExceptionHandler.uncaughtException(thread, exception)
            }
    } catch (t: Throwable) {
        // 如果处理异常时又抛出异常...
    }
}

9. 总结

Kotlin 协程 launch 的执行流程可以概括为:

  1. 创建协程上下文:组合父作用域和自定义上下文

  2. 创建协程实例:根据启动模式创建 StandaloneCoroutine 或 LazyStandaloneCoroutine

  3. 启动协程:通过 CoroutineStart 决定启动方式

  4. 调度执行:通过 ContinuationInterceptor (通常是调度器) 决定运行线程

  5. 构建 Continuation:将协程体转换为状态机

  6. 执行协程体:通过 resume 机制逐步执行

  7. 处理完成/取消:正常完成或取消时清理资源

你可能感兴趣的:(kotlin - 协程 launch 源码分析)