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

为何Kotlin协程GlobalScope搭配Dispatchers.Main会抛出异常?

问题:使用Dispatchers.Main启动协程抛出RuntimeException,切换至IO/Default调度器可正常运行

问题重现代码

fun main(args: Array<String>) {
        
        println(" Program Starts to run")
        
        GlobalScope.launch(Dispatchers.Main) {
            delay(2000)
            println("Program inside global scope launch")
        }
    
        println(" Program Ends Now")
    }

抛出的异常

Exception in thread "main" java.lang.RuntimeException: Exception while
trying to handle coroutine exception  at
kotlinx.coroutines.CoroutineExceptionHandlerKt.handlerException(CoroutineExceptionHandler.kt:38)

原因分析

Dispatchers.Main是为UI主线程设计的调度器,但在纯JVM运行环境(比如直接执行main函数的场景)下,kotlinx-coroutines-core核心库本身并没有提供它的默认实现。只有引入对应UI平台的协程扩展库(比如Android的kotlinx-coroutines-android、Swing的kotlinx-coroutines-swing)后,Dispatchers.Main才有可用的线程调度逻辑。

而Dispatchers.IO和Dispatchers.Default是kotlinx-coroutines-core自带的调度器,基于JVM线程池实现,无需额外依赖就能正常工作。

另外还有一个潜在问题:即便解决了Main调度器的依赖问题,当前代码的main函数会直接执行完毕退出,协程还没来得及执行就会被终止,你也看不到协程内的打印输出。

解决方案

1. 引入对应平台的Main调度器依赖

如果是Android开发,在build.gradle中添加:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:版本号'

如果是桌面Swing/JavaFX应用,对应添加kotlinx-coroutines-swing或kotlinx-coroutines-javafx依赖,版本号需与kotlinx-coroutines-core保持一致。

2. 阻塞主线程等待协程完成

修改main函数,用runBlocking包裹逻辑,避免主线程提前退出:

fun main(args: Array<String>) {
    println(" Program Starts to run")

    runBlocking {
        launch(Dispatchers.Main) {
            delay(2000)
            println("Program inside global scope launch")
        }
    }

    println(" Program Ends Now")
}

也可以通过join()方法单独等待目标协程完成:

fun main(args: Array<String>) {
    println(" Program Starts to run")

    val job = GlobalScope.launch(Dispatchers.Main) {
        delay(2000)
        println("Program inside global scope launch")
    }

    runBlocking { job.join() } // 等待协程执行完毕
    println(" Program Ends Now")
}

3. 避免使用GlobalScope(推荐)

GlobalScope的生命周期不受控制,容易引发内存泄漏,建议使用自定义CoroutineScope:

fun main(args: Array<String>) {
    println(" Program Starts to run")

    val mainScope = CoroutineScope(Dispatchers.Main)
    val job = mainScope.launch {
        delay(2000)
        println("Program inside global scope launch")
    }

    runBlocking { job.join() }
    mainScope.cancel() // 手动取消Scope释放资源
    println(" Program Ends Now")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 06:35:11