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

为何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 14:22:09