为什么挂起函数在finally中会抛出异常

Ser*_*any 2 kotlin kotlinx.coroutines kotlin-coroutines

正如标题所说,为什么挂起函数会抛出异常finally

对于常规函数,finally-block 会执行所有函数:

import kotlinx.coroutines.*

fun main() {
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Caught $exception")
    }
    val job = GlobalScope.launch(handler) {
        launch {
            // the first child
            try {
                println("inside try")
                delay(1000)
            } finally {

                println("Children are cancelled, but exception is not handled until all children terminate")

                Thread.sleep(1000)
                println("thread.sleep executed")
                //foo()
                println("The first child finished its non cancellable block")

            }
        }
        launch {
            // the second child
            delay(10)
            println("Second child throws an exception")
            throw ArithmeticException()
        }
    }

    Thread.sleep(1000000)
    println("complete")
}
Run Code Online (Sandbox Code Playgroud)

例如,当我Thread.sleep(1000)这样做时,会打印:

“第一个孩子完成了不可取消的块”

但如果我将该行更改为delay(1000),则不会。

根据我的理解,在finally-block 中,异常(如果存在)会在执行整个块后抛出。

但在这种情况下,delay会导致提前抛出此异常。

另一方面,则Thread.sleep不然。

有人可以帮忙解释一下吗?

fun*_*ude 5

Kotlin 中的挂起函数与阻塞函数的工作方式不同。当您取消 a 时,在取消后的第一次暂停时,即使您处于块中Job,执行也会停止。如果您在块中使用而不是,则不会发生暂停,因为是阻塞,而不是暂停,因此整个块都会被执行。finallyThread.sleep(1000)delay(1000)finallyThread.sleep()finally

请注意,在挂起函数内使用阻塞函数是一种反模式,应该避免!

要在不使用阻塞函数的情况下实现此所需行为,请按照此处withContext(NonCancellable) {...}所述进行使用。

您的示例代码应如下所示:

fun main() {
  val handler = CoroutineExceptionHandler { _, exception ->
    println("Caught $exception")
  }
  val job = GlobalScope.launch(handler) {
    launch {
      // the first child
      try {
        println("inside try")
        delay(1000000)
      } finally {
        withContext(NonCancellable) {
          println("Children are cancelled, but exception is not handled until all children terminate")

          delay(1000) // This suspension cannot be cancelled
          println("delay executed")
          //foo()
          println("The first child finished its non cancellable block")
        }
      }
    }
    launch {
      // the second child
      delay(10)
      println("Second child throws an exception")
      throw ArithmeticException()
    }
  }

  Thread.sleep(1000000)
  println("complete")
}
Run Code Online (Sandbox Code Playgroud)

输出:

inside try
Second child throws an exception
Children are cancelled, but exception is not handled until all children terminate
delay executed
The first child finished its non cancellable block
Caught java.lang.ArithmeticException
Run Code Online (Sandbox Code Playgroud)