Skip to content

Kotlin 协程 Scope 作用域、Job 状态机与异常隔离 ​

回到总览:并发与运行时底座
相关模块:Kotlin 协程 Dispatchers、CoroutineContext 与构建器 · Kotlin 协程 Mutex 互斥锁、共享变量与无锁并发

一句话定义 ​

Kotlin 协程提出了 结构化并发 (Structured Concurrency) 原理:所有协程必须在固定的 CoroutineScope 作用域中启动;通过 Job 状态机管理父子协程的生命周期取消,并通过 SupervisorJob 实现子协程异常的精准隔离防护。

代码索引 ​

对应 Lab:coroutine_execution_flow

为什么需要 ​

  • 为什么在 Android 开发中盲目使用 GlobalScope.launch 是极其严重的内存泄漏隐患?
    • 一句话答:GlobalScope 的生命周期与整个 App 进程一样长;如果在 Activity 中用它启动耗时任务,页面销毁后协程不会自动取消,强持 Activity 对象引发内存泄漏。
  • 默认情况下子协程抛出未捕获异常,为什么会导致父协程以及兄弟协程全被取消?
    • 一句话答:这是双向异常传播机制:子协程崩溃会将异常向上传递给父协程,父协程收到后取消自身,并向下取消所有其他兄弟子协程;如果需要隔离异常(子崩溃不影响兄弟),必须使用 SupervisorJob 或 supervisorScope。

底层机制 ​

1. Job 状态机演进图 ​

2. 普通 Job vs SupervisorJob 异常传播对比 ​

图注补充:2. 向下取消所有兄弟;1. 异常被 Supervisor 拦截隔离。

Android / Flutter / Web / Backend 对照 ​

异常与作用域Kotlin 协程Dart (Flutter)Go 语言
生命周期作用域viewModelScope / lifecycleScopeState.dispose 手动 cancelcontext.WithCancel(ctx)
异常隔离机制SupervisorJob() / supervisorScopeIsolate 之间默认彻底隔离recover() 防 panic 崩溃

常见场景 ​

1. 使用 supervisorScope 隔离局部异常 ​

kotlin
suspend fun fetchDashboardData() = supervisorScope {
    // 两个子请求并行发起
    val userDeferred = async { fetchUserProfile() }
    val bannerDeferred = async { fetchBanners() } // 即使 banner 失败抛异常

    val user = try { userDeferred.await() } catch (e: Exception) { null }
    val banner = try { bannerDeferred.await() } catch (e: Exception) { null }

    DashboardUiState(user, banner) // 保证 user 数据依然能正常展示!
}

对应实验 ​

各章节内已嵌入跳转链接;此处汇总全部 Lab:

Lab说明
coroutine_execution_flowMain → IO → Main 线程切换、async/await、状态机等效执行流验证

复习检查题 ​

  1. 在 Kotlin 协程中,Job 与 SupervisorJob 处理子协程异常的核心区别是什么?

    答:默认的 Job 采用双向异常传播机制:任何一个子协程发生未捕获异常时,都会向上抛给父 Job,导致父 Job 取消自身并向下取消所有其他兄弟子协程;而 SupervisorJob 实现了异常隔离,某个子协程崩溃不会影响父 Job,也不会取消其他同级兄弟子协程。

  2. 为什么在 ViewModel 中推荐使用 viewModelScope 启动协程?

    答:因为 viewModelScope 绑定了 ViewModel 的生命周期。当 ViewModel 对应的页面销毁(触发 onCleared())时,viewModelScope 会自动调用内部 Job 的 cancel(),递归取消该作用域下启动的所有耗时协程,彻底避免了后台无用任务浪费 CPU/网络资源及内存泄漏。

速记 ​

  • 结构化并发:绝不用 GlobalScope,Activity/ViewModel 使用自带 Scope。
  • 异常隔离:多并行任务用 supervisorScope,防止单个子任务失败干掉整个页面。
  • 取消协作:协程取消是协作式的,耗时循环内需检测 ensureActive() 或 yield()。

站点构建时间:2026/8/24 23:43:17