withContext(NonCancellable)可以让挂起函数不被取消。从效果上来看,有点像java中的interrupt打断sleep来中断线程
1. 效果验证
- 使用 withContext(NonCancellable),代码如下
import kotlinx.coroutines.*
fun main() = runBlocking{
// # 9
/**
* 使用withContext(NonCancellable)后,即使取消,它里面的内容都会执行完,不使用的话,就会只delay后面就不执行了
*/
val job = launch {
try {
repeat(1000) {
println("job: I'm sleeping $it")
delay(1000L)
}
}finally {
// println("job: I'm running finally")
// delay(10L)
// println("job: And I'v just delayed for 1 sec beca")
println("job: I'm running finally")
withContext(NonCancellable){
delay(1000L)
}
println("job: And I'v just delayed for 1 sec beca")
}
}
delay(1300L)
println("main: I'm tired of waiting!")
job.cancelAndJoin()
println("main: Now I can quit.")
}
打印日志如下:
job: I'm sleeping 0
job: I'm sleeping 1
main: I'm tired of waiting!
job: I'm running finally
job: And I'v just delayed for 1 sec beca
main: Now I can quit.
- 不适用withContext(NonCancellable), 代码如下:
import kotlinx.coroutines.*
fun main() = runBlocking{
// # 9
/**
* 使用withContext(NonCancellable)后,即使取消,它里面的内容都会执行完,不使用的话,就会只delay后面就不执行了
*/
val job = launch {
try {
repeat(1000) {
println("job: I'm sleeping $it")
delay(1000L)
}
}finally {
println("job: I'm running finally")
delay(10L)
println("job: And I'v just delayed for 1 sec beca")
// println("job: I'm running finally")
// withContext(NonCancellable){
//
// delay(1000L)
//
// }
// println("job: And I'v just delayed for 1 sec beca")
}
}
delay(1300L)
println("main: I'm tired of waiting!")
job.cancelAndJoin()
println("main: Now I can quit.")
}
日志如下:
job: I'm sleeping 0
job: I'm sleeping 1
main: I'm tired of waiting!
job: I'm running finally
main: Now I can quit.
从日志可以看出,代码被从delay位置打断
2. 为什么说这个打断只是像java中线程的sleep一样呢
验证代码如下:
import kotlinx.coroutines.*
fun main() = runBlocking{
val job = launch {
try {
repeat(1000) {
println("job: I'm sleeping $it")
delay(1000L)
}
}finally {
// println("job: I'm running finally")
// delay(10L)
// println("job: And I'v just delayed for 1 sec beca")
println("job: I'm running finally")
// withContext(NonCancellable){
// delay(1000L)
// }
cpuExecuteTime(5)
println("job: And I'v just delayed for 1 sec beca")
}
}
delay(1300L)
println("main: I'm tired of waiting!")
job.cancelAndJoin()
println("main: Now I can quit.")
}
/**
* @param time second
*/
private suspend fun cpuExecuteTime(time:Long){
var nextPrintTime = System.currentTimeMillis()
var i = 0
while (i < time) {
if (System.currentTimeMillis() >= nextPrintTime) {
println("cup execute i = ${i++} second")
nextPrintTime += 1000L
}
}
}
打印的日志如下:
job: I'm sleeping 0
job: I'm sleeping 1
main: I'm tired of waiting!
job: I'm running finally
cup execute i = 0 second
cup execute i = 1 second
cup execute i = 2 second
cup execute i = 3 second
cup execute i = 4 second
job: And I'v just delayed for 1 sec beca
main: Now I can quit.
可以看到哪怕是cancel了,cpuExecuteTime这个函数也还在继续执行直到完成,cancel方法并没有起作用。
这里引入了一个cpuExecuteTime的新函数,作用几乎空转一段时间,反正就是保持cpu运行。
因此这里可以得出结论,cancel无法打断这种非delay或者sleep的执行代码。这就有点像java中调用Thread的interrupt打断线程了。