协程的基本取消
package cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
/**
* 一个用户也许关闭了一个启动了协程的界面,
* 现在协程的执行结果已经不再被需要了,这时,它应该是可以被取消的
*/
fun main() = runBlocking {
val job = launch {
repeat(1000) { i ->
println("this is i = $i")
delay(500L)
}
}
delay(1300L)
println("main:waiting...")
job.cancel() // 取消job
job.join() // 等待job执行结束
println("main:exiting...")
// output:
// this is i = 0
// this is i = 1
// this is i = 2
// main:waiting...
// main:exiting...
}
协程的cancelAndJoin
package cancel
import kotlinx.coroutines.*
/**
* 协程的取消是 协作 的。一段协程代码必须协作才能被取消。
* 所有 kotlinx.coroutines 中的挂起函数都是可被取消的 。
* 它们检查协程的取消,并在取消时抛出 CancellationException。
* 如果协程正在执行计算任务,并且没有检查取消的话,那么它是不能被取消的,
*/
fun main() = runBlocking {
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // 一个执行计算的循环,只是为了占用 CPU
// 每秒打印消息两次
if (System.currentTimeMillis() >= nextPrintTime) {
println("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L)
println("main:waiting...")
job.cancelAndJoin() // 取消一个job并且等待它结束
println("main:exiting...")
// output:
// job: I'm sleeping 0 ...
// job: I'm sleeping 1 ...
// job: I'm sleeping 2 ...
// main:waiting...
// job: I'm sleeping 3 ...
// job: I'm sleeping 4 ...
// main:exiting...
}
使计算代码可取消
package cancel
import kotlinx.coroutines.*
/**
* 协程是可以被取消的
* 取消的两种方式:
* 1、定期调用挂起函数来检查取消 job.cancel() // 取消job ====>job.join() // 等待job执行结束
* 2、显式的检查取消状态 isActive
*/
fun main() = runBlocking {
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (isActive) { // // 可以被取消的计算循环
// 每秒打印消息两次
if (System.currentTimeMillis() >= nextPrintTime) {
println("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L)
println("main:waiting...")
job.cancelAndJoin() // 取消一个job并且等待它结束
println("main:exiting...")
// output:
// job: I'm sleeping 0 ...
// job: I'm sleeping 1 ...
// job: I'm sleeping 2 ...
// main:waiting...
// main:exiting...
}
携程在finally中释放资源和执行操作
package cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
/**
* 协程在被取消时抛出 CancellationException 的可被取消的挂起函数
* eg:
* try {……} finally {……} 表达式以及 Kotlin 的 use 函数
* 一般在协程被取消的时候执行它们的终结动作
*/
fun main() = runBlocking {
val job = launch {
try {
repeat(1000) { i ->
println("this is i = $i")
delay(500L)
}
}finally {
println("job finally canceled")
}
}
delay(1300L)
println("main:waiting...")
job.cancel() // 取消job
job.join() // 等待job执行结束
println("main:exiting...")
// output:
// this is i = 0
// this is i = 1
// this is i = 2
// main:waiting...
// job finally canceled
// main:exiting...
}
协程在withContext(NonCancellable)执行操作
package cancel
import kotlinx.coroutines.*
/**
* 需要挂起一个被取消的协程,可以将相应的代码包装在 withContext(NonCancellable) {……} 中,
* 并使用 withContext 函数以及 NonCancellable 上下文
*/
fun main() = runBlocking {
val job = launch {
try {
repeat(1000) { i ->
println("this is i = $i")
delay(500L)
}
}finally {
// println("job finally canceled")
withContext(NonCancellable){
println("job: I'm running finally")
delay(1000L)
println("job: 我会延迟1s取消,因为我是不可被取消的")
}
}
}
delay(1300L)
println("main:waiting...")
job.cancel() // 取消job
job.join() // 等待job执行结束
println("main:exiting...")
// output:
// this is i = 0
// this is i = 1
// this is i = 2
// main:waiting...
// job: I'm running finally
// job: 我会延迟1s取消,因为我是不可被取消的
// main:exiting...
}