协程进阶:异常 06. 取消异常的透明性 (Cancellation Transparency)

本篇解析 example-exceptions-06.kt。探讨协程在取消过程中的异常“透明”特性。

1. 核心概念:透明且未包装

在 Kotlin 协程中,取消异常(CancellationException)是透明的。

特点:

  • 不被包装:当一个协程被取消时,它会抛出 CancellationException。这个异常不会被包装 in 其他异常中,而是以原始形式抛出。
  • 重新抛出:如果你捕获了 CancellationException,通常建议将其重新抛出。这有助于协程库正确地传播取消信号,并完成结构化并发的清理工作。

2. 代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
val job = GlobalScope.launch(handler) {
val inner = launch {
launch {
launch { throw IOException() } // 1. 原始异常发生
}
}
try {
inner.join()
} catch (e: CancellationException) {
println("Rethrowing CancellationException...")
throw e // 2. 重新抛出取消信号
}
}
  • 执行逻辑
    1. 最深层的子协程抛出 IOException
    2. 这导致整个 inner 协程树被取消。
    3. 父协程在 inner.join() 处捕获到 CancellationException
    4. 即使父协程重新抛出了 CancellationException,最外层的 handler 最终捕获到的依然是那个引发一切的原始异常:IOException

3. 开发者感悟

“取消透明性”保证了异常源头不会被掩盖。在复杂的嵌套协程中,你不需要担心中间层级的 try-catch 会让真实的报错信息丢失。只要遵循“捕获后重新抛出”的原则,协程库就能确保原始的错误根源最终能到达你的全局异常处理器中。

,