Kotlin 作用域是否在引擎盖下无声地处理异常/故障?
我有以下代码片段用于测试目的Kotlin 作用域是否在引擎盖下无声地处理异常/故障?,kotlin,exception,coroutine,kotlin-coroutines,Kotlin,Exception,Coroutine,Kotlin Coroutines,我有以下代码片段用于测试目的 fun main() { val myScope = CoroutineScope(Dispatchers.Default) + Job() myScope.launch { val job = async { delay(1000) throw RuntimeException("shiiiet") } try { job.await()
fun main() {
val myScope = CoroutineScope(Dispatchers.Default) + Job()
myScope.launch {
val job = async {
delay(1000)
throw RuntimeException("shiiiet")
}
try {
job.await()
} catch (ret: RuntimeException){
throw RuntimeException("yooo!")
}
}
try {
Thread.sleep(5000)
} catch(e: Exception){
}
println("wohoooo!")
}
我以为流量永远不会到达最后一行,但我错了。我看到它印在屏幕上。我想到的原因是launch
会将异常传播到父作用域,并且由于父作用域不处理它,它会在到达print语句时使JVM崩溃
这是因为父作用域在其子作用域失败、收到CancellationException并被忽略后被取消了吗 在您的示例中,您尝试了多种
throw
和catch
方法
async
按预期工作-当您等待它时,您可以捕获异常。但是,如果您启动一个协同例程,默认的线程.uncaughtExceptionHandler
只会将结果打印到控制台
即使你这样做了
myScope.launch {
....
}.invokeOnCompletion { e -> println("Exception: $e") }
您仍然可以在控制台上获得额外的结果
本文解释了传播规则和处理异常的不同调用类型
有关如何在“main”co例程中捕获异常的示例:
fun main() = runBlocking {
try {
GlobalScope.launch {
delay(10)
throw Exception("You don't catch me in main.")
}
launch {
delay(10)
throw Exception("You catch me in main.")
}
delay(100)
println("Never reached.")
} catch(e: Exception) {
println("Caught in main: ${e.cause}")
}
println("The end")
}
顶级启动失败
不会使JVM崩溃,也不应该让JVM崩溃。崩溃的线程也不会使JVM崩溃。这是真的,但我不知何故认为异常会通过作用域一直传播到主线程。默认调度程序不负责主线程。在普通Java上,主线程甚至不运行事件循环,因此根本无法调度协同路由。您必须使用runBlocking在其上显式创建一个事件循环。您的代码总是打印从未到达
以及你看不见我。
此外,分派器。Unconfined
不使用“主上下文”,不管这意味着什么,它在调用launch
和resume
的地方启动并恢复协同路由,在这些调用中,没有任何线程限制。Ups,用你看不见我
我的意思是你在main()里抓不到我
。。。。我需要再调查一下调度员。给我几个小时的时间…你不可能在一个线程中捕捉到一个并发启动的协同程序的异常,这个线程已经开始做其他事情了。只有在null分派的意外情况下,您才会看到由于上述原因而从launch(Unconfined)
引发的异常,它在不分派的情况下执行。如果在抛出异常之前添加delay(10)
,则该行为将在协同路由挂起时立即消失。然而,即使不挂起,我也无法从launch
捕获异常。@Mark在进一步阅读和测试后,我删除了答案中的错误部分。谢谢你指出这一点。我添加了一个关于如何捕获“主协同例程”的示例……您所做的是捕获由失败的子协同例程导致的CancellationException
。您没有捕获并处理原始异常,您只是将其作为取消原因附加。引发CancellationException
的代码行是delay(100)
,因为它是一个可取消的挂起调用。但是,这并没有阻止runBlocking
作用域失败,因此这实际上并不构成异常处理。