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

关于Kotlin协程执行顺序不明确及代码输出不可预测的原因咨询

Kotlin协程执行顺序不明确及代码输出不可预测的原因咨询

嗨,我来帮你拆解一下这个问题,你碰到的其实就是协程并发调度带来的正常现象,并非什么奇怪的bug哦。

先理清楚你的代码逻辑:你启动了三个独立的协程job1、job2、job3,它们都做了1秒延迟后打印"World!"。主线程(也就是main函数所在的协程)先打印"Hello,"和job1的活跃状态,然后调用job1.join()等待它完成,之后再打印job1的完成状态,最后依次等待job2和job3完成。

你预期job1完成后立刻打印它的完成状态,再看到另外两个"World!",但实际却是三个"World!"都挤在了job1完成状态打印的前面,这背后有两个核心原因:

  • 协程的并发调度特性:三个协程几乎是同时启动的,它们的delay(1000L)也几乎同步开始计时。1秒后,这三个协程的打印任务会被协程调度器(默认是Dispatchers.Default,基于线程池实现)同时唤醒,随后它们会争抢线程资源来执行打印操作。这时候三个"World!"的输出顺序本身就是不确定的——谁先抢到线程谁先打印,这属于正常的并发竞争场景。

  • join()仅等待目标协程,不阻塞其他协程:当你调用job1.join()时,主线程会挂起,直到job1完成。但job2和job3此时已经处于运行状态,它们的delay也接近结束。当job1完成、主线程恢复准备打印job1的完成状态时,job2和job3的打印任务可能已经被调度器安排执行了,所以它们的"World!"会先于主线程的打印操作输出。

举个生活化的例子:就像你让三个人同时开始计时,1秒后喊"World",你自己先等第一个人喊完,然后准备记录他完成了,但另外两个人可能和第一个人几乎同时喊出声,所以你还没来得及记录,就先听到了另外两个人的声音。

如果想达到你预期的输出效果,只要把job2和job3的启动放在job1.join()之后就行,这样它们会在job1完成后才开始执行,自然就会在job1的完成状态打印之后输出:

suspend fun main() {
    val job1 = GlobalScope.launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    println(job1)
    job1.join()
    println(job1)
    
    // 等job1完成后再启动另外两个协程
    val job2 = GlobalScope.launch {
        delay(1000L)
        println("World!")
    }
    val job3 = GlobalScope.launch {
        delay(1000L)
        println("World!")
    }
    job2.join()
    job3.join()
}

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 13:38:01