kotlin异常处理之----取消异常CancellationException与其他异常的区别,协程异常处理顺序

CancellationException异常是协程专门用来取消协程而使用,与其他异常在处理上是有区别的

  • 协程内部使用CancellationException来进行取消操作,这个异常会被忽略掉。
  • 当子协程取消后,不会取消父协程。(如果是其他异常,父协程也完蛋喽!)
  • 如果一个协程遇到CancellationException以外的异常,它将使用该异常来取消父协程。当父协程和子协程都结束后,异常才会被父协程处理。

下面的例子中,println("异常捕获 ${exception.message}")这句话是最后被执行的,因为上面的第三点提到,父协程处理异常是要在所有的子协程全部都执行完毕。

step1:当第二个子协程抛出异常后,向父协程抛出CancellationException来取消父协程。

step2:父协程给第一个子协程传递一个异常,第一个子协程捕获到了异常,执行finally清理资源。(这里清理资源时必须使用withContext(NonCancellable)包裹, 因为这样才不会被其他异常打扰,完成资源清理工作)

step3:当子协程都执行完成后,这里就是第一个子协程的finally执行完毕后,才使用handler处理第二个子协程抛出的异常。

@Test
fun coroutineExceptionHandlerTest2() = runBlocking<Unit> {
    var handler = CoroutineExceptionHandler{ _ , exception ->
        println("异常捕获 ${exception.message}")
    }
    var job1 = GlobalScope.launch(handler) {
        launch {
            try {
                println("第一个子协程进入")
                delay(Long.MAX_VALUE)
            } catch (e : java.lang.Exception) {
                println("第一个子协程捕获到异常,${e.message}")
            } finally {
                withContext(NonCancellable) {
                    println("第一个子协程准备清理资源")
                    delay(5000)
                    println("第一个子协程准备清理资源完毕")
                }
            }
        }
        launch {
            println("第二个子协程进入")
            delay(1000)
            throw ArithmeticException("抛出一个算数异常!!!!!!!!!")
        }
    }
    job1.join()
}
第一个子协程进入
第二个子协程进入
第一个子协程捕获到异常,Parent job is Cancelling
第一个子协程准备清理资源
第一个子协程准备清理资源完毕
异常捕获 抛出一个算数异常!!!!!!!!!

猜你喜欢

转载自blog.csdn.net/mldxs/article/details/127178858
今日推荐