kotlin: 协程的启动模式: ATOMIC
一,例一:atomic模式启动
代码:
//处理按钮点击事件
binding.button3.setOnClickListener {
runBlocking {
log(1)
val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
log(2)
}
job.cancel()
log(3)
}
}
运行结果:
我们创建了协程后立即 cancel,但由于是 ATOMIC
模式,
因此协程一定会被调度,因此 1、2、3 一定都会输出
二,例二,比较default模式
代码:
//处理按钮点击事件
binding.button4.setOnClickListener {
runBlocking {
log(1)
val job = GlobalScope.launch(start = CoroutineStart.DEFAULT) {
log(2)
}
job.cancel()
log(3)
}
}
运行结果:
这次是
在第一次调度该协程时如果 cancel 就已经调用,那么协程就会直接被 cancel 而不会有任何调用,
当然也有可能协程开始时尚未被 cancel,那么它就可以正常启动了。
所以改用
DEFAULT
模式,在第一次调度该协程时如果 cancel 就已经调用,那么协程就会直接被 cancel 而不会有任何调用,
当然也有可能协程开始时尚未被 cancel,那么它就可以正常启动了。
所以改用
DEFAULT
模式后,2 有可能会输出,也可能不会三,例三
代码:
//处理按钮点击事件
binding.button5.setOnClickListener {
runBlocking {
log(1)
val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
log(2)
delay(1000)
log(3)
}
job.cancel()
log(4)
job.join()
}
}
运行结果:
cancel 调用一定会将该 job 的状态置为 cancelling,只不过ATOMIC
模式的协程在启动时无视了这一状态
delay
会使得协程体的执行被挂起,1000ms 之后再次调度后面的部分,因此 3 会在 2 执行之后 1000ms 时输出。对于
ATOMIC
模式,我们已经讨论过它一定会被启动,实际上在遇到第一个挂起点之前,它的执行是不会停止的,
而
delay
是一个 suspend 函数,这时我们的协程迎来了自己的第一个挂起点,
恰好
delay
是支持 cancel 的,因此后面的 3 将不会被打印