kotlin: 不要轻易打破协程的父子结构
一,例子一
代码:定义一个线程池
val fixedDispatcher = Executors.newFixedThreadPool(2) {
Thread(it, "MyFixedThread").apply { isDaemon = false }
}.asCoroutineDispatcher()
调用:
//处理按钮点击事件
binding.button1.setOnClickListener {
runBlocking {
// 父协程
val parentJob = launch(fixedDispatcher) {
// 1,注意这里
launch(Job()) { // 子协程1
var i = 0
while (isActive) {
Thread.sleep(500L)
i ++
println("First i = $i")
}
}
launch { // 子协程2
var i = 0
while (isActive) {
Thread.sleep(500L)
i ++
println("Second i = $i")
}
}
}
delay(2000L)
parentJob.cancel()
parentJob.join()
println("End")
}
}
运行结果:

第二个子协程正常停止,第一个子协程停不下来,
问题原因:
launch(Job()){} 这个写法使“子协程 1”已经不是 parentJob 的子协程了,
它的父 Job 是我们在 launch 当中传入的 Job() 对象。
所以,当我们调用 parentJob.cancel() 的时候,无法取消“子协程 1”
二,改进:恢复正常的协程父子结构:
代码:
//处理按钮点击事件
binding.button2.setOnClickListener {
runBlocking {
// 父协程
val parentJob = launch(fixedDispatcher) {
// 1,注意这里,取消了参数
launch { // 子协程1
var i = 0
while (isActive) {
Thread.sleep(500L)
i ++
println("First i = $i")
}
}
launch { // 子协程2
var i = 0
while (isActive) {
Thread.sleep(500L)
i ++
println("Second i = $i")
}
}
}
delay(2000L)
parentJob.cancel()
parentJob.join()
println("End")
}
}
运行结果:

取消了launch(Job())的参数,使协程的父子结构保持正常,
parentJob 与它内部的子协程 1、子协程 2 之间是父子关系,
因此它们两个都是会响应协程取消的事件的
浙公网安备 33010602011771号