Kotlin 协程上下文 #

一、CoroutineContext 概述 #

协程上下文是一组元素的集合,定义了协程的行为。

1.1 主要元素 #

元素 说明
Job 协程作业
Dispatcher 调度器
CoroutineName 协程名称
CoroutineExceptionHandler 异常处理器

1.2 组合上下文 #

kotlin
val context = Dispatchers.IO + CoroutineName("MyCoroutine")

二、Dispatchers 调度器 #

2.1 Default #

CPU 密集型任务:

kotlin
launch(Dispatchers.Default) {
    // 排序、过滤、计算等
    val result = heavyComputation()
}

2.2 IO #

IO 密集型任务:

kotlin
launch(Dispatchers.IO) {
    // 网络请求、文件操作、数据库操作
    val data = fetchData()
}

2.3 Main #

主线程(UI 线程):

kotlin
launch(Dispatchers.Main) {
    // UI 更新
    textView.text = "Hello"
}

2.4 Unconfined #

不限制线程:

kotlin
launch(Dispatchers.Unconfined) {
    println("Thread: ${Thread.currentThread().name}")
    delay(100)
    println("Thread: ${Thread.currentThread().name}")  // 可能不同
}

2.5 自定义调度器 #

kotlin
val singleThreadDispatcher = newSingleThreadContext("MyThread")
val fixedDispatcher = newFixedThreadPoolContext(4, "MyPool")

launch(singleThreadDispatcher) {
    // 在单线程执行
}

三、Job #

3.1 获取 Job #

kotlin
fun main() = runBlocking {
    val job = launch {
        delay(1000)
        println("Completed")
    }
    
    println("isActive: ${job.isActive}")
    println("isCompleted: ${job.isCompleted}")
}

3.2 Job 状态 #

kotlin
fun main() = runBlocking {
    val job = launch {
        delay(1000)
    }
    
    // 状态
    job.isActive      // 是否活跃
    job.isCompleted   // 是否完成
    job.isCancelled   // 是否取消
    
    // 操作
    job.cancel()      // 取消
    job.join()        // 等待完成
    job.cancelAndJoin()  // 取消并等待
}

3.3 父子关系 #

kotlin
fun main() = runBlocking {
    val parentJob = launch {
        launch {
            delay(1000)
            println("Child 1")
        }
        
        launch {
            delay(500)
            println("Child 2")
        }
    }
    
    parentJob.join()  // 等待所有子协程完成
}

3.4 取消传播 #

kotlin
fun main() = runBlocking {
    val parent = launch {
        repeat(5) { i ->
            launch {
                delay(1000)
                println("Child $i")
            }
        }
    }
    
    delay(1500)
    parent.cancel()  // 取消父协程,所有子协程也被取消
}

四、CoroutineScope #

4.1 创建作用域 #

kotlin
// 使用 CoroutineScope
val scope = CoroutineScope(Dispatchers.Default)

scope.launch {
    println("Running in scope")
}

// 使用 MainScope(Android)
val mainScope = MainScope()
mainScope.launch {
    // 在主线程执行
}

4.2 自定义作用域 #

kotlin
class MyService {
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    
    fun doWork() {
        scope.launch {
            // 执行任务
        }
    }
    
    fun destroy() {
        scope.cancel()  // 取消所有协程
    }
}

4.3 lifecycleScope(Android) #

kotlin
class MyFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        lifecycleScope.launch {
            // 生命周期感知
            val data = fetchData()
            view.textView.text = data
        }
    }
}

4.4 viewModelScope(Android) #

kotlin
class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            val data = repository.fetch()
            _data.value = data
        }
    }
}

五、上下文切换 #

5.1 withContext #

kotlin
suspend fun loadData(): String {
    // 切换到 IO 线程
    return withContext(Dispatchers.IO) {
        fetchData()
    }
}

5.2 链式切换 #

kotlin
suspend fun process() {
    withContext(Dispatchers.IO) {
        // IO 操作
        val data = fetchData()
        
        withContext(Dispatchers.Default) {
            // CPU 计算
            process(data)
        }
    }
}

5.3 保留上下文 #

kotlin
suspend fun example() {
    println("Current: ${coroutineContext[Job]}")
    
    withContext(Dispatchers.IO) {
        // Job 相同,Dispatcher 不同
        println("Current: ${coroutineContext[Job]}")
    }
}

六、CoroutineName #

6.1 命名协程 #

kotlin
fun main() = runBlocking {
    launch(CoroutineName("Worker-1")) {
        println("Running: ${coroutineContext[CoroutineName]}")
    }
    
    launch(CoroutineName("Worker-2")) {
        println("Running: ${coroutineContext[CoroutineName]}")
    }
}

6.2 调试 #

kotlin
fun main() = runBlocking {
    launch(CoroutineName("DataLoader")) {
        println("Loading data...")
    }
}
// 使用 -Dkotlinx.coroutines.debug 启动调试

七、CoroutineExceptionHandler #

7.1 全局异常处理 #

kotlin
fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Caught: $exception")
    }
    
    launch(handler) {
        throw Exception("Error!")
    }
}

7.2 在作用域中使用 #

kotlin
class MyService {
    private val handler = CoroutineExceptionHandler { _, e ->
        println("Error: ${e.message}")
    }
    
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO + handler)
    
    fun doWork() {
        scope.launch {
            throw Exception("Something went wrong")
        }
    }
}

八、实战示例 #

8.1 网络请求封装 #

kotlin
class Repository {
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    
    suspend fun <T> safeApiCall(
        apiCall: suspend () -> T
    ): Result<T> {
        return try {
            Result.success(apiCall())
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    fun destroy() {
        scope.cancel()
    }
}

8.2 并发限制 #

kotlin
suspend fun <T, R> List<T>.mapConcurrent(
    concurrency: Int,
    transform: suspend (T) -> R
): List<R> = coroutineScope {
    val semaphore = Semaphore(concurrency)
    
    map { item ->
        async {
            semaphore.withPermit {
                transform(item)
            }
        }
    }.awaitAll()
}

九、最佳实践 #

9.1 选择合适的 Dispatcher #

kotlin
// IO 操作 → Dispatchers.IO
withContext(Dispatchers.IO) { }

// CPU 计算 → Dispatchers.Default
withContext(Dispatchers.Default) { }

// UI 更新 → Dispatchers.Main
withContext(Dispatchers.Main) { }

9.2 使用结构化并发 #

kotlin
// 推荐:使用作用域
class MyService {
    private val scope = CoroutineScope(SupervisorJob())
    
    fun cleanup() {
        scope.cancel()
    }
}

9.3 处理异常 #

kotlin
val handler = CoroutineExceptionHandler { _, e ->
    log.error("Coroutine error", e)
}

scope.launch(handler) {
    // 协程代码
}

十、总结 #

协程上下文要点:

元素 说明
Dispatchers 线程调度
Job 协程作业
CoroutineName 协程名称
CoroutineExceptionHandler 异常处理

下一步,让我们学习 协程取消与超时

最后更新:2026-03-27