题目
如何启动和取消一个Kotlin协程?
信息
- 类型:问答
- 难度:⭐
考点
协程启动,协程取消,协程作用域
快速回答
启动协程的常用方式:
- 使用
launch启动不返回结果的协程 - 使用
async启动需要返回结果的协程
取消协程的关键操作:
- 调用
Job.cancel()取消单个协程 - 通过
CoroutineScope.cancel()取消作用域内所有协程
一、协程启动原理
Kotlin协程通过协程构建器启动,需在协程作用域(CoroutineScope)中执行。主要启动方式:
- launch:启动新协程,不返回结果,返回
Job对象用于控制生命周期 - async:启动新协程,返回
Deferred对象(类似Future),可通过await()获取结果
二、代码示例
import kotlinx.coroutines.*
fun main() = runBlocking {
// 1. 使用 launch 启动协程
val job = launch {
repeat(5) { i ->
delay(500L)
println("Job: I'm sleeping $i ...")
}
}
// 2. 使用 async 启动协程
val deferred = async {
delay(1000L)
"Hello World"
}
delay(1300L) // 等待一段时间
job.cancel() // 取消第一个协程
println("Job cancelled")
println("Async result: ${deferred.await()}") // 获取async结果
}三、协程取消机制
- 取消原理:协程取消是协作式的,需在协程内部检查取消状态
- 关键检查点:
delay()、yield()等挂起函数会自动检查取消 - 手动检查:使用
ensureActive()或isActive判断
四、最佳实践
- 始终在协程中处理可能取消的操作(如IO)
- 使用
try {...} finally {...}释放资源,结合withContext(NonCancellable)执行不可取消操作 - 避免在
finally中调用挂起函数(除非使用NonCancellable)
五、常见错误
- 错误:未处理取消导致资源泄漏
错误示例:
修正方案:launch { val file = openFile() // 可能泄漏 delay(1000) // 可能在此处被取消 file.close() // 不会执行 }launch { val file = openFile() try { delay(1000) } finally { withContext(NonCancellable) { file.close() } } } - 错误:在已取消作用域启动新协程
错误示例:val scope = CoroutineScope(Job()) scope.cancel() scope.launch { ... } // 立即取消
六、扩展知识
- 结构化并发:通过作用域管理协程生命周期,避免全局泄漏
- SupervisorJob:子协程失败不影响同级协程
- 协程上下文:使用
Dispatchers.IO等指定调度器