kotlin: 合作式取消(判断 Job 的状态)

一,例子:cpu密集型任务会使cancel()无效

代码:

        //处理按钮点击事件
        binding.button1.setOnClickListener {
            runBlocking {
                val startTime = System.currentTimeMillis()
                val job = launch(Dispatchers.Default) {
                    var nextPrintTime = startTime
                    var i = 0
                    while (i < 5) {
                        if (System.currentTimeMillis() >= nextPrintTime) {
                            println("I'm sleeping $i")
                            i++
                            nextPrintTime += 500
                        }
                    }
                }
                delay(1200)
                println("Time to finish")
                job.cancelAndJoin()
                println("Done")
            }
        }

运行结果:

image

看代码运行结果的输出,job 任务并没有按我们设想的那样打印三次就被 cancel。
而是在调用 cancel 方法后,仍然在继续打印,直到 5 次打印完才退出。
这是为什么呢?
这就是因为 job 是一个 CPU 密集型任务,一直抢占着 CPU,
使得 cancel() 命令来不及调度
如何解决这个问题?
我们可以在循环时使用 isActive 属性检查 job 是否处于活跃状态

二,例子,改进,使生效

代码:

        //处理按钮点击事件
        binding.button2.setOnClickListener {
            runBlocking {
                val startTime = System.currentTimeMillis()
                val job = launch(Dispatchers.Default) {
                    var nextPrintTime = startTime
                    var i = 0
                    while (i < 5 && isActive) {
                        if (System.currentTimeMillis() >= nextPrintTime) {
                            println("I'm sleeping $i")
                            i++
                            nextPrintTime += 500
                        }
                    }
                }
                delay(1200)
                println("Time to finish")
                job.cancelAndJoin()
                println("Done")
            }
        }

运行结果:

image

三,协程合作式取消的三个函数

  • ensureActive()[3]
  • isActive()[4]
  • yield()[5]

代码:

        //处理按钮点击事件
        binding.button2.setOnClickListener {
            runBlocking {
                val startTime = System.currentTimeMillis()
                val job = launch(Dispatchers.Default) {
                    var nextPrintTime = startTime
                    var i = 0
                    while (i < 5) {
                        ensureActive()
                        if (System.currentTimeMillis() >= nextPrintTime) {
                            println("I'm sleeping $i")
                            i++
                            nextPrintTime += 500
                        }
                    }
                }
                delay(1200)
                println("Time to finish")
                job.cancelAndJoin()
                println("Done")
            }
        }

运行结果:

image

 

posted @ 2025-08-09 13:41  刘宏缔的架构森林  阅读(18)  评论(0)    收藏  举报