You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何runBlocking无法触发传入的CoroutineExceptionHandler?

Why doesn't runBlocking trigger the passed CoroutineExceptionHandler?

Great question! Let's break down why this behavior happens—since CoroutineExceptionHandler behaves differently depending on which coroutine builder you're using.

First, the core rule of CoroutineExceptionHandler

CoroutineExceptionHandler is built to handle uncaught exceptions from top-level or root coroutines—coroutines that don't have a parent coroutine to delegate exception handling to. When such a coroutine throws an uncaught exception, the handler kicks in to process it.

Why GlobalScope.launch(handler) works

When you use GlobalScope.launch, you're creating a top-level coroutine. It has no parent coroutine that would catch its exceptions, so the CoroutineExceptionHandler you pass acts as the fallback for handling uncaught errors. That's exactly why your first test runs smoothly—the exception is caught and printed as expected.

Why runBlocking(handler) fails

runBlocking is a special blocking coroutine builder. Its whole purpose is to bridge the coroutine world with regular blocking threads. Unlike GlobalScope.launch, runBlocking directly rethrows any uncaught exceptions from its coroutine block to the thread that called it.

Think of it this way: runBlocking is meant to act like a standard blocking function. If you had a regular fun() that threw an exception, it would crash the thread, right? runBlocking follows the same logic—it doesn't route exceptions to the CoroutineExceptionHandler you pass; it just propagates them up to the calling thread, which is why your test crashes.

How to make CoroutineExceptionHandler work with runBlocking

If you want to use the handler alongside runBlocking, apply it to a child coroutine launched inside the runBlocking block—not to runBlocking itself. Here's the adjusted test code:

@Test fun test() {
    val handler = CoroutineExceptionHandler { _, exception ->
        println("CoroutineExceptionHandler got $exception")
    }
    runBlocking {
        // Launch a child coroutine with the handler attached
        launch(handler) {
            throw IllegalAccessException("Just testing")
        }
    }
    Thread.sleep(300)
}

In this case, the child coroutine is a root coroutine relative to its parent (the runBlocking coroutine doesn't handle its exceptions by default), so the CoroutineExceptionHandler will catch the exception and print your message as intended.

Key takeaway

CoroutineExceptionHandler doesn't work with runBlocking's top-level block because runBlocking is designed to propagate exceptions directly to the calling thread. Use the handler on child coroutines inside runBlocking if you need to catch their uncaught exceptions.

内容的提问来源于stack exchange,提问作者Elye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:29:55