You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父协程遇异常后子协程未取消?SupervisorJob作用解析

协程作用域异常行为疑问解答

为什么测试代码里子协程抛CancellationException后,其他子协程还能执行?

核心原因是**CancellationException在Kotlin协程中属于「正常取消信号」,而非异常失败**:

  • 当协程抛出CancellationException时,只会终止当前协程本身,不会向上传播导致父协程或兄弟协程被取消。
  • 看测试代码的结构:外层scope.launch启动的协程并没有被取消,它在延迟4秒后依然能正常启动第二个子协程,所以会输出child 2 coroutine。
  • 只有当子协程抛出非CancellationException类型的异常时,才会触发普通Job作用域的连锁取消逻辑——父协程被取消,所有兄弟子协程也跟着终止。

使用CoroutineScope(Dispatchers.IO + SupervisorJob())的区别

普通默认Job和SupervisorJob的核心差异在于异常传播规则:

  • 普通Job(默认):任意子协程抛出非CancellationException的异常时,会立即取消父协程以及所有其他子协程,整个作用域直接失效。
  • SupervisorJob:子协程抛出异常(包括非CancellationException)时,仅终止该出错的子协程,父协程和其他兄弟子协程不受影响,实现了子协程的独立容错。

测试代码

val scope = CoroutineScope(Dispatchers.IO)

Button(onClick = {
    scope.launch {
        launch {
            println("child 1 coroutine")
            delay(2.seconds)
            throw CancellationException()
        }
        delay(4.seconds)
        launch {
            println("child 2 coroutine")
        }
    }
}) {
    Text(text = "Scope check")
}

异常处理示例代码

val handler = CoroutineExceptionHandler { _, e ->
    println("handled: ${e.message}")
}
val scope = CoroutineScope(Dispatchers.IO + handler)
Button(
    modifier = Modifier.padding(innerPadding),
    onClick = {
        scope.launch {
            supervisorScope {
                launch {
                    println("child 1 coroutine")
                    delay(1.seconds)
                    throw Exception("Child 1 Exception")
                }
                delay(4.seconds)
                launch {
                    println("child 2 coroutine")
                }
            }
        }
    }) {
    Text(text = "Scope check")
}

内容的提问来源于stack exchange,提问作者PRATHIV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 01:40:03