kotlin的父子协程关系

关于协程的父子关系,从如下一段代码的运行结果来分析
复制代码
import kotlinx.coroutines.*
import java.net.URL

suspend fun fetchResponse(code: Int, delay: Int) = coroutineScope {
    try {
        val response = async {
            URL("http://httpstat.us/$code?sleep=$delay").readText()
        }.await()
        println(response)
    } catch(ex: CancellationException) {
        println("${ex.message} for fetchResponse $code")
    }
}

runBlocking {
    val handler = CoroutineExceptionHandler {_, ex ->
        println("exception handled: ${ex.message}")
    }

    val job = launch(Dispatchers.IO + SupervisorJob() + handler) {
        // 协程1
        launch{fetchResponse(202, 1000)} // 协程2
        launch{fetchResponse(404, 2000)} // 协程3
        launch{fetchResponse(200, 3000)} // 协程4
    }
    job.join()
}
复制代码

如上运行的结果是:
202 Accepted
Parent job is Cancelling for fetchResponse 200
exception handled: http://httpstat.us/404?sleep=2000

按照定义:使用 SupervisorJob,子协程的失败不会影响其余子协程。一个 SupervisorJob不会取消它自己或它的子协程。而且,SupervisorJob也不会传播异常,它会让子协程自己处理异常。

但是上述在协程3发生异常之后,协程4竟然被取消了;也就是说在launch中的SupervisorJob()不起作用?
如果说不起作用的话,那么异常应该继续往外传播,可是异常却在handler拦住了

这里我们先分析各个协程是job还是SupervisorJob
fetchResponse是由coroutineScope包着,所以coroutineScope是job类型
launch会创建一个新的协程默认Job,所以协程234均为Job
那么协程1是什么类型的呢?从运行结果显示应该是Job而不是SupervisorJob。那么为什么是Job?
因为一个新的协程总是会被赋予一个新的Job(),它在这个例子中覆盖了SupervisorJob。SupervisorJob是通过 scope.launch创建的协程的parentjob
这也就解释了为什么协程3异常的时候,他的兄弟协程4被取消;协程1向上抛出异常,但是被他的父协程SupervisorJob拦住了让他自己处理异常,所以协程1只能将异常交给handler

综上所述:协程1234均为Job,协程234的父协程是协程1,协程1的父协程是SupervisorJob

posted @   LCAC  阅读(204)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示