使用runBlocking时Kotlin协程代码执行顺序疑问:输出为何与预期不符?
Kotlin协程launch执行顺序问题解析
原问题代码与现象
原代码如下:
private fun runBlockingWithLaunch() { print(1) runBlocking { print(2) launch { print(3) delay(2_000) print(4) } print(5) } print(6) }
预期输出是123546,但实际运行得到125346。
核心原因:协程的非抢占式调度
Kotlin协程默认是非抢占式调度——除非当前协程主动调用挂起函数(比如delay)让出线程执行权,否则其他协程无法打断当前协程的同步代码执行。
具体执行逻辑:
- 先执行
print(1),随后进入runBlocking(它会阻塞当前线程,直到内部所有协程执行完毕)。 - 执行
print(2),调用launch创建子协程,但这个子协程不会立即启动——当前主协程(runBlocking内部的协程)还在运行同步代码,没有主动挂起,线程不会切换到子协程。 - 主协程继续执行
print(5),直到这行代码跑完,线程才会调度之前创建的子协程,执行print(3)。 - 子协程调用
delay(2000)挂起,线程回到主协程等待;2秒后子协程恢复,执行print(4)。 - 最后
runBlocking结束,执行print(6)。
所以最终输出是125346。
修改版本的差异解释
版本1:主协程delay(2),子协程delay(1)
private fun runBlockingWithLaunch() { print(1) runBlocking { print(2) launch { delay(1) // 新增挂起 print(3) delay(2_000) print(4) } delay(2) // 新增挂起 print(5) } print(6) }
输出:125346
原因:
- 主协程执行到
delay(2)主动挂起,线程开始调度子协程。 - 子协程执行
delay(1)后挂起,此时主协程的挂起时间还剩1ms(总共2ms),线程回到主协程等待剩余时间。 - 主协程挂起时间到,先恢复执行
print(5),之后线程才会再次调度子协程执行print(3)。
版本2:主协程delay(3),子协程delay(1)
private fun runBlockingWithLaunch() { print(1) runBlocking { print(2) launch { delay(1) // 新增挂起 print(3) delay(2_000) print(4) } delay(3) // 新增挂起 print(5) } print(6) }
输出:123546
原因:
- 主协程执行
delay(3)挂起,线程调度子协程。 - 子协程执行
delay(1)后恢复,先执行print(3),接着调用delay(2000)再次挂起。 - 此时主协程的挂起时间还剩2ms(总共3ms-已过1ms),线程继续等待主协程挂起结束,之后才执行
print(5)。
内容的提问来源于stack exchange,提问作者umutcan sahin
相关产品推荐
相关产品推荐

