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

Kotlin协程无挂起点时取消生效的原因解析

为何无挂起点的Kotlin协程仍会被取消?
launch {
    // If we comment 'cancel()' console shows:
    //    B
    //    C
    //    A
    // So there is no suspension point.
    cancel()
    launch { println("A") } // Will not be printed
    coroutineScope { println("B") }
    println("C") // Will not be printed
}.join()

当调用cancel()后,原本以为因为没有挂起点,取消不会生效,但实际协程执行完coroutineScope中的println("B")后就被取消了,后续的println("C")没有执行;而注释掉cancel()时,打印顺序是B、C、A,说明协程从未挂起。为什么取消操作在这里会生效?


核心原因:cancel()标记状态,coroutineScope主动检查取消

  • cancel()的作用是标记取消状态,而非立即终止
    调用cancel()后,当前协程的取消状态会被置为true,但协程不会立刻停止运行——除非遇到挂起点、主动检查取消状态,或者调用了会检查取消状态的挂起函数。

  • launch { println("A") }不执行的原因
    在已被标记为取消的协程上下文中启动新协程时,新协程会直接继承取消状态,不会执行其块内代码,所以A不会被打印。

  • coroutineScope是关键:挂起函数内置取消检查
    尽管coroutineScope的块内没有挂起点,但它本身是一个挂起函数,内部包含了取消检查逻辑:

    1. 首先,它会同步执行块内的println("B")(因为块内没有子协程需要等待);
    2. 在coroutineScope准备返回前,它会主动检查当前协程的取消状态。发现已被标记取消后,会抛出CancellationException,这个异常会终止当前协程的执行,因此后续的println("C")不会运行。
  • 纠正误解:取消并非仅在挂起时生效
    取消的核心是协程的取消状态被标记,任何主动检查该状态的代码都会触发终止逻辑。除了挂起函数会自动检查外,你也可以手动调用ensureActive()或yield()来检查取消状态,让协程在无挂起点的情况下也能响应取消。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:42:35