协程学习(八)协程简单的使用之协程的异常传播机制

115 阅读1分钟

在协程中如果发生了异常,那么这个异常的传播路径是什么样的呢,

先来说一下异常传播时比较好理解传播途径

下面上例子

@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        CoroutineScope(Dispatchers.IO).launch {
            var job1 = launch {
                launch {
                    launch {
                        launch {
                            delay(1000)
                        }
                    }
                }.join()
                println("--------job1 执行完成-----------")
            }
            var job2 = launch {
                launch {
                    launch {
                        launch {
                            launch {
                                delay(100)
                                throw ClassCastException("报错了")
                            }
                        }
                    }
                }
            }
            delay(200)
            println("------父协程执行完毕-----------")
        }
        delay(2000)
    }
}

结果:

Exception in thread "DefaultDispatcher-worker-2 @coroutine#8" java.lang.ClassCastException: 报错了
	at com.tsm.opencv.Tsm$main$1$1$job2$1$1$1$1$1.invokeSuspend(Tsm.kt:29)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [CoroutineId(2), "coroutine#2":StandaloneCoroutine{Cancelling}@2c66815a, Dispatchers.IO]

Process finished with exit code 0

在这个例子中, runBlocking 作用域中创建了一个 CoroutineScope 并指定了他的新的作用域,那么他就省升级为顶级父协程,同时在 CoroutineScope 作用域中创建了2个 launch 的嵌套子作用域, 在 launch 2 子协程中发生了异常,但是他导致了 launch 1中的没有打印,同时 父协程中的结束也没有打印,

在没有特殊处理的情况下,子协程如果发生了异常,那么这个异常会逐级向上抛出,直到顶级父作用域,顶级作用域接受到异常后,会取消抛出异常协程的兄弟协程

image.png

图片中就展示了异常的传播过程,laucn 2先抛出异常,随后沿着红色路线逐级上抛,到达顶级父协程后,再有顶级父协程延颜色路线再逐级向下抛

如果在创建父协程时使用supervisorScope 或者supervisorjob 那么异常传递到顶级父协程后将不会再向下传递