kotlin - 协程 launch 源码分析
CoroutineScope(Dispatchers.Main).launch {}
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
}
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
}
根据启动模式创建不同类型的协程实例:
根据启动模式创建不同类型的协程实例:
StandaloneCoroutine: 默认立即启动的协程
LazyStandaloneCoroutine: 延迟启动的协程(当调用start或join时才启动)
private open class StandaloneCoroutine(
parentContext: CoroutineContext,
active: Boolean
) : AbstractCoroutine
override fun handleJobException(exception: Throwable): Boolean {
handleCoroutineException(context, exception)
return true
}
}
coroutine.start()
调用链:
public fun
start(block, receiver, this)
}
CoroutineStart
是一个枚举类,定义了不同的启动方式:
public enum class CoroutineStart {
DEFAULT, // 立即调度执行
LAZY, // 延迟启动
ATOMIC, // 原子方式启动(不可取消)
UNDISPATCHED // 立即在当前线程执行第一段代码
}
以 DEFAULT
启动模式为例:
internal operator fun
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)
}
}
}
// 其他模式处理...
}
}
startCoroutineCancellable
最终会调用到协程的创建和执行:
internal fun
receiver: R,
completion: Continuation
) = runSafely(completion) {
// 创建 Continuation
createCoroutineUnintercepted(receiver, completion)
// 拦截处理(如添加调度器)
.intercepted()
// 开始执行
.resumeCancellableWith(Result.success(Unit))
}
当协程被调度时:
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)
}
}
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
}
协程内部的异常通过 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) {
// 如果处理异常时又抛出异常...
}
}
Kotlin 协程 launch
的执行流程可以概括为:
创建协程上下文:组合父作用域和自定义上下文
创建协程实例:根据启动模式创建 StandaloneCoroutine
或 LazyStandaloneCoroutine
启动协程:通过 CoroutineStart
决定启动方式
调度执行:通过 ContinuationInterceptor
(通常是调度器) 决定运行线程
构建 Continuation:将协程体转换为状态机
执行协程体:通过 resume
机制逐步执行
处理完成/取消:正常完成或取消时清理资源