为何使用SupervisorJob()后第二个协程仍被取消?JVM协程问题
问题原因及解决方案
你代码里的核心问题是:内层两个协程的父Job并不是你定义的SupervisorJob,而是外层launch创建的普通Job。
当你执行CoroutineScope(SupervisorJob() + handler).launch { ... }时,这个外层launch会自动生成一个普通Job,作为你传入的SupervisorJob的子Job。而内层的两个launch默认继承这个普通Job作为父——普通Job的规则是只要有一个子协程抛出未捕获异常,所有同级子协程都会被取消,父Job也会失败,这就是第二个协程被取消的原因。
解决方案
方案一:去掉外层多余的launch
直接在SupervisorJob的作用域下启动两个协程,让它们的父Job就是你定义的SupervisorJob:
fun main() { val handler = CoroutineExceptionHandler { _, _ -> println("handling the error") } val scope = CoroutineScope(SupervisorJob() + handler) scope.launch { println(Thread.currentThread().name) println("...") delay(500) throw RuntimeException("failing first coroutine") } scope.launch { println(Thread.currentThread().name) println("fetching some data over the network") delay(1000) println("Done") } Thread.sleep(2000) }
方案二:用supervisorScope包裹内层协程
在外层launch里添加supervisorScope块,让内层协程在局部的Supervisor作用域下运行,这样它们的父Job会变成Supervisor类型,失败不会互相影响:
fun main() { val handler = CoroutineExceptionHandler { _, _ -> println("handling the error") } CoroutineScope(SupervisorJob() + handler).launch { println(Thread.currentThread().name) supervisorScope { launch { println(Thread.currentThread().name) println("...") delay(500) throw RuntimeException("failing first coroutine") } launch { println(Thread.currentThread().name) println("fetching some data over the network") delay(1000) println("Done") } } } Thread.sleep(2000) }
内容的提问来源于stack exchange,提问作者Genuine _8
相关产品推荐
相关产品推荐

