协程进阶:异常 05. 异常聚合 (Aggregation)

本篇解析 example-exceptions-05.kt。探讨当多个子协程同时抛出异常时,协程库是如何处理这些冲突的。

1. 核心概念:第一个异常获胜

当多个子协程因为不同的异常而失败时,基本的聚合规则是:“取第一个抛出的异常”

特点:

  • 第一个异常:作为主异常,传递给 CoroutineExceptionHandler
  • 后续异常:会被绑定到主异常的 suppressed 列表中(仅限 JDK 7+)。

2. 代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
val handler = CoroutineExceptionHandler { _, exception ->
// 捕获到的是第一个异常:IOException
// 被抑制的是第二个异常:ArithmeticException
println("Caught $exception with suppressed ${exception.suppressed.contentToString()}")
}

val job = GlobalScope.launch(handler) {
launch {
try { delay(Long.MAX_VALUE) }
finally { throw ArithmeticException() } // 后发生的异常
}
launch {
delay(100)
throw IOException() // 先发生的异常
}
}

3. 开发者感悟

这是一个非常严密的并发错误处理机制。它保证了即便在复杂的并行任务中,也不会漏掉任何一个报错信息。所有的异常都能通过主异常的 suppressed 列表进行溯源。在调试高并发 Bug 时,检查 suppressed 列表是寻找真凶的关键。

,