为什么CoroutineExceptionHandler没有捕获/处理我的异常?

时间:2018-05-05 16:24:51

标签: kotlin kotlinx.coroutines

在此代码中,为什么handler仅打印JobCancellationException而不是SocketException的堆栈跟踪? foo内的launch函数肯定会抛出SocketException,那么会发生什么呢?

suspend fun foo() {
  val job = coroutineContext[Job]!!
  val socket = Socket()

  job.invokeOnCompletion(onCancelling = true) {
    if (!socket.isClosed) {
      socket.close()
    }
  }

  // non-routable address -> timeout
  // will throw SocketException after socket.close() is called above
  socket.connect(InetSocketAddress("10.0.0.0", 1234), 2000)
}

fun test() = runBlocking {
  val handler = CoroutineExceptionHandler { _, throwable ->
    throwable.printStackTrace()
  }

  val job = launch(DefaultDispatcher + handler) {
    foo()
  }

  delay(100)
  job.cancelAndJoin()
  delay(100)
}

1 个答案:

答案 0 :(得分:0)

我无法告诉您为什么CoroutineExceptionHandler没有捕获launch中引发的异常。但是我可以告诉你两件事-

  1. 我已验证您发现的行为-您是正确的,未捕获到异常。
  2. 通过实验,我学会了如何在CoroutineExceptionHandler中捕获异常。

以下是显示如何捕获它的代码:

fun f() = runBlocking {
    val eh = CoroutineExceptionHandler { _, e -> trace("exception handler: $e") }
    val cs1 = CoroutineScope(Dispatchers.Default)
    val j1 = cs1.launch(eh + CoroutineName("first"))  {
        trace("launched")
        delay(1000)
        throw RuntimeException("error!")
    }
    trace("joining j1")
    j1.join()
    val cs2 = CoroutineScope(Dispatchers.Default + eh)
    val j2 = cs2.launch(CoroutineName("second"))  {
        trace("launched")
        delay(1000)
        throw RuntimeException("error!")
    }
    trace("joining j2")
    j2.join()
    trace("after join")
}
f()

控制台输出:

[main @coroutine#1]: joining j1
[DefaultDispatcher-worker-1 @first#2]: launched
[DefaultDispatcher-worker-1 @first#2]: exception handler: java.lang.RuntimeException: error!
[main @coroutine#1]: joining j2
[DefaultDispatcher-worker-1 @second#3]: launched
[DefaultDispatcher-worker-3 @second#3]: exception handler: java.lang.RuntimeException: error!
[main @coroutine#1]: after join

关键要点在于,如果您在自定义launch上调用CoroutineScope,则直接提供给CoroutineExceptionHandler构造函数或CoroutineScope的任何launchlaunch ed协程中引发异常时执行。

希望有帮助!

更新

我发现了为什么没有捕获到异常的原因。请参阅我的答案here