Kotlin协程中的Job详解
Job是Kotlin协程中表示协程任务的核心概念,它提供了对协程生命周期的控制和管理的功能。
Job的基本概念
Job是协程的句柄,具有以下特点:
- 每个协程都会返回一个Job对象
- 用于控制协程的生命周期
- 可以建立父子关系,形成结构化的并发
Job的创建方式
1. 通过launch创建Job
val job = GlobalScope.launch {
// 协程体
}
2. 通过async创建Deferred(Job的子接口)
val deferred = GlobalScope.async {
// 协程体,返回结果
}
// Deferred继承自Job,额外提供await()方法获取结果
Job的生命周期状态
Job有以下几种状态:
- New (新建):LAZY模式下的初始状态
- Active (活跃):正在执行
- Completing (完成中):已完成但子协程还在运行
- Cancelling (取消中):正在取消但还未完全取消
- Cancelled (已取消)
- Completed (已完成)
状态转换关系:
New → Active → Completing → Completed
↘ Cancelling → Cancelled
Job的核心功能
1. 取消协程
job.cancel() // 取消协程
job.cancel("取消原因", CancellationException()) // 带原因的取消
2. 等待协程完成
job.join() // 挂起当前协程,直到目标协程完成
3. 取消与等待组合
job.cancelAndJoin() // 先取消再等待完成
4. 状态检查
job.isActive // 是否活跃
job.isCompleted // 是否完成
job.isCancelled // 是否已取消
Job的父子关系
父子关系特性
- 父Job取消时,所有子Job会自动取消
- 子Job失败时,默认会取消父Job(可通过SupervisorJob改变)
- 父Job会等待所有子Job完成
父子关系创建方式
val parentJob = Job()
val childJob = GlobalScope.launch(parentJob) {
// 子协程
}
Job的常见使用场景
1. 结构化并发管理
fun fetchData() {
val parentJob = Job()
launch(parentJob) { fetchUser() }
launch(parentJob) { fetchPosts() }
// 取消所有相关协程
parentJob.cancel()
}
2. 超时控制
val job = launch {
try {
withTimeout(3000) {
longRunningTask()
}
} catch (e: TimeoutCancellationException) {
// 处理超时
}
}
3. 资源清理
val job = launch {
try {
// 执行任务
} finally {
// 确保资源清理
releaseResources()
}
}
Job的扩展功能
1. 协程取消时的回调
job.invokeOnCompletion { cause: Throwable? ->
// 协程完成或取消时的回调
cause?.let { println("协程被取消: $it") }
}
2. 使用SupervisorJob
val supervisorJob = SupervisorJob()
launch(supervisorJob) {
// 子协程失败不会影响其他子协程
}
Job与协程上下文
Job是CoroutineContext的一部分:
launch(Dispatchers.IO + CoroutineName("my-coroutine") + job) {
// 协程体
}
实际应用示例
1. 任务组合管理
fun loadMultipleDataSources() {
val parentJob = Job()
val userJob = launch(parentJob + Dispatchers.IO) { fetchUser() }
val postsJob = launch(parentJob + Dispatchers.IO) { fetchPosts() }
// 等待所有完成
runBlocking {
userJob.join()
postsJob.join()
}
// 或者取消所有
parentJob.cancel()
}
2. 生命周期感知的Job管理
class MyViewModel : ViewModel() {
private val jobs = mutableListOf<Job>()
fun fetchData() {
val job = viewModelScope.launch {
// 执行任务
}
jobs.add(job)
job.invokeOnCompletion {
jobs.remove(job)
}
}
override fun onCleared() {
jobs.forEach { it.cancel() }
}
}
Job是Kotlin协程并发控制的基础,合理使用Job可以实现:
- 精确的协程生命周期管理
- 结构化的并发任务组织
- 高效的资源清理机制
- 灵活的取消控制策略
理解并掌握Job的使用是编写健壮协程代码的关键。