还没进行源码分析,下面的理解只是从异常发生机制来解释:
一般来说,协程中子协程出现了异常,会传递到顶级父协程,父协程这时会取消其余的子协程,
-
默认情况下(非SupervisorScope): 如果父协程没有使用
supervisorScope
创建子协程,那么当一个子协程出现异常被取消时,其他子协程也会被取消。这种情况下,被取消的子协程会抛出CancellationException
。 -
SupervisorScope: 如果父协程使用了
supervisorScope
创建子协程,那么当一个子协程出现异常被取消时,其他子协程不会受到影响,它们会继续执行。被取消的子协程会将异常传递给它的父协程,但不会取消其他子协程。
这里发生的异常聚合肯定是指第一种情况,使用CoroutineExceptionHandler
来实现异常聚合。通过设置一个统一的异常处理器,可以捕获父协程及其所有子协程中抛出的异常,从而统一进行处理,简单来讲就是让异常变得更直观,更容易管理,而且其余异常绑定在第一个异常之上。
下面代码来分析:
使用CoroutineExceptionHandler捕获:
@Test
fun testException() = runBlocking<Unit> {
val handler = CoroutineExceptionHandler{_, exception ->
println("caught $exception ${exception.suppressed.contentToString()}")
}
val scope = CoroutineScope(Dispatchers.Default).launch(handler) {
//第二个子协程
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw ArithmeticException()
}
}
//第一个子协程
launch {
delay(100)
throw RuntimeException()
}
}
scope.join()
}
运行结果: