为何含SupervisorJob的协程作用域会取消子协程?求逻辑解析
为什么使用SupervisorJob的协程作用域会取消子launch任务?
我不需要解决方法,只想理解逻辑——毕竟SupervisorJob本不应取消子协程。
代码示例
suspend fun main() { val scope = CoroutineScope(SupervisorJob()) scope.launch { launch { f1() } launch { f2() } launch { error() } } } suspend fun f1() { delay(300) println("f1") } suspend fun f2() { delay(300) println("f2") }
运行结果
无任何输出,且错误未抛出。
补充疑问
若改为以下写法则正常,这是为什么?
scope.launch { .. } scope.launch { .. } scope.launch { .. }
逻辑解释
核心差异在于协程的层级关系和Job类型:
第一种写法的问题:
- 你在
scope.launch创建的协程内部,又启动了三个子launch。这个外层的scope.launch默认使用普通Job(不是SupervisorJob),它是三个内部launch的直接父Job。 - 普通Job的特性是:一旦子Job失败,会立即取消自身以及所有其他子Job。所以
error()抛出异常后,外层的scope.launch协程被取消,连带取消了执行f1()和f2()的两个子launch,导致没有输出。 - 同时,协程的异常默认会被内部异常处理器捕获,不会向上抛出到
main函数,所以看不到错误信息。
- 你在
第二种写法的正常原因:
- 三个
scope.launch直接挂载在CoroutineScope(SupervisorJob())下,它们的直接父Job是SupervisorJob。 SupervisorJob的核心特性是子Job失败不会影响同级其他子Job:当其中一个launch抛出异常时,只会取消该异常launch自身的子树(这里没有子树),不会影响另外两个执行f1()和f2()的协程,所以它们能正常执行并输出结果。
- 三个
内容的提问来源于stack exchange,提问作者senior salaga
相关产品推荐
相关产品推荐

