协作式取消:isActive 与 ensureActive
通过检查 isActive 并调用 ensureActive,使协程支持取消。
协作式取消:isActive 与 ensureActive 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
为什么需要协作式取消
Kotlin 协程使用协作式取消:只有在被取消的协程通过检查自身取消状态进行协作时,它才会停止。紧凑的 CPU 循环在执行检查之前不会停止。
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
var i = 0
while (true) { i++ } // never checks — never cancels!
}
delay(100)
job.cancel()
println("cancel sent but loop kept running until process ended")
}检查 isActive
isActive 是 CoroutineScope 上的一个属性,在收到取消请求后会返回 false。在循环中检查它可以让协程进行协作。
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
var i = 0
while (isActive) {
i++
}
println("Loop exited after $i iterations")
}
delay(10)
job.cancel()
job.join()
}ensureActive()
如果协程已被取消,ensureActive() 会抛出 CancellationException。它可以直接替代 if (!isActive) throw CancellationException()。
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
repeat(1_000_000) {
ensureActive() // throws if cancelled
// heavy computation here
}
} catch (e: CancellationException) {
println("Cancelled at iteration")
throw e
}
}
delay(5)
job.cancel()
job.join()
}yield() 作为协作检查点
yield() 会短暂挂起协程,使调度器能够检查取消状态并运行其他协程。
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
repeat(10) { i ->
yield() // cooperative cancellation point + gives up scheduler
println("Step $i")
}
}
delay(2)
job.cancel()
job.join()
println("Done")
}isActive 与 ensureActive
对于条件逻辑(例如优雅地跳出循环),请使用 isActive。当您希望立即将取消作为异常传播时,请使用 ensureActive()。
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
repeat(100) { i ->
if (!isActive) {
println("Stopping at $i, cleaning up...")
return@launch
}
// work
}
}.also { delay(5); it.cancel(); it.join() }
}CancellationException 很特殊
CancellationException 不会传播给父级——它表示正常取消。切勿吞掉它;请始终重新抛出它,或让它继续传播。
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
delay(1000)
} catch (e: CancellationException) {
println("Caught cancellation, rethrowing")
throw e // important!
}
}
delay(50)
job.cancel()
job.join()
println("Job state: ${job.isCancelled}")
}CPU 密集型工作中的取消
对于 CPU 密集型工作,请在自然的检查点插入 ensureActive() 或 yield(),以便及时响应取消。
import kotlinx.coroutines.*
suspend fun heavyCompute(n: Int): Long {
var result = 0L
for (i in 0..n) {
ensureActive()
result += i
}
return result
}
fun main() = runBlocking {
val job = launch(Dispatchers.Default) {
println(heavyCompute(1_000_000))
}
delay(10)
job.cancel()
job.join()
}自定义挂起函数中的 isActive
您可以在任何挂起函数中通过 coroutineContext.isActive,或使用 currentCoroutineContext().isActive 来访问 isActive。
import kotlinx.coroutines.*
suspend fun checkable() {
while (currentCoroutineContext().isActive) {
delay(10)
println("tick")
}
}
fun main() = runBlocking {
val job = launch { checkable() }
delay(35)
job.cancel()
job.join()
}带资源清理的取消
即使采用协作式取消,也可以在 finally 块中清理资源——取消异常仍会穿过这些块继续传播。
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
repeat(100) { i ->
ensureActive()
delay(20)
println("Working $i")
}
} finally {
println("Cleanup done")
}
}
delay(50)
job.cancel()
job.join()
}使用 isActive 轮询
轮询循环非常适合使用 isActive:持续轮询,直到协程被取消。
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
while (isActive) {
println("Polling...")
delay(100)
}
println("Poller stopped")
}
delay(350)
job.cancel()
job.join()
}与 Thread.interrupted() 的区别
与 Java 线程不同,Kotlin 协程不依赖中断标志。取消通过异常和作用域状态来建模,因此可以组合并保持结构化。
import kotlinx.coroutines.*
fun main() = runBlocking {
// Kotlin way: cooperative via isActive / ensureActive
launch {
ensureActive()
println("Kotlin coroutine: cancellation is explicit and structured")
}
}快速检查
协程被取消时,哪个函数会立即抛出异常?
回顾
协作式取消需要显式的检查点:isActive 用于有条件地退出,ensureActive() 用于立即抛出异常,yield() 用于挂起并让出线程。切勿吞掉 CancellationException。
常见问题解答
「协作式取消:isActive 与 ensureActive」课时是免费的吗?
是的 — 「协作式取消:isActive 与 ensureActive」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「协作式取消:isActive 与 ensureActive」这节课中我会学到什么?
通过检查 isActive 并调用 ensureActive,使协程支持取消。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「协作式取消:isActive 与 ensureActive」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 协作式取消:isActive 与 ensureActive
- withTimeout 与 withTimeoutOrNull
- 使用 finally 与 NonCancellable 清理资源
- 协程层次结构中的取消传播