嵌套Kotlin协程作用域执行顺序疑问及原理解析
问题解析:Kotlin协程中嵌套子协程的执行顺序
你的核心误解在于混淆了结构化并发的作用域完成规则和协程构建器的阻塞特性,下面拆解原因:
1. launch协程构建器的非阻塞特性
launch是非阻塞式的——调用它启动子协程时,会立即返回当前协程的执行流,不会等待子协程执行完毕。
在你的代码里,第一个launch的执行流程是:
- 延迟2000ms后,调用
launch { println("nested child") }启动嵌套子协程,这行代码瞬间完成,不会阻塞当前协程 - 紧接着执行
println("parent")
而嵌套子协程启动后,需要等待协程调度器分配执行时间,所以它的打印操作会晚于parent的打印,哪怕它没有设置delay。
2. 结构化并发规则的真实含义
官方文档所说的「外层作用域必须等待所有子协程完成后才能结束」,指的是外层作用域的生命周期会覆盖所有子协程,但这并不改变父协程本身的代码执行顺序:
- 父协程的代码会按编写顺序依次执行,不会被子协程的启动阻塞
- 只有当父协程的所有代码执行完毕后,才会等待所有子协程完成,再结束自身的作用域
你看到的输出里,nested child最终会被打印出来,而不是被丢弃,这正是结构化并发的体现——外层的runBlocking会等待所有嵌套协程完成后才退出。
3. 如何让nested child在parent之前打印
如果需要让嵌套子协程的执行结果在parent之前输出,需要主动阻塞父协程,等待子协程完成,常用两种方式:
方式一:使用Job.join()
fun exampleCoroutine() { println("Corutine started") runBlocking { launch { delay(2000) // 保存子协程的Job对象,调用join()等待其完成 val nestedJob = launch { println("nested child") } nestedJob.join() println("parent") } launch { delay(1000) println("in the second coroutine") } println("Hello") } }
方式二:使用coroutineScope包裹
coroutineScope会创建一个子作用域,并且阻塞当前协程,直到该作用域内的所有子协程完成:
fun exampleCoroutine() { println("Corutine started") runBlocking { launch { delay(2000) coroutineScope { launch { println("nested child") } } println("parent") } launch { delay(1000) println("in the second coroutine") } println("Hello") } }
修改后输出就会变成:
Corutine started Hello in the second coroutine nested child parent
内容的提问来源于stack exchange,提问作者user3196429
相关产品推荐
相关产品推荐

