在 Kotlin 中,协程(Coroutines)是一种轻量级的并发编程模型,用于处理异步、并发和非阻塞代码。 它与传统线程有本质区别,并提供了更高效、更易用的并发编程方式。

1 线程的并发模型

1.1 核心特点
  • 内核级调度: 线程由操作系统内核管理,创建和销毁都需要内核介入,切换涉及上下文切换,开销较大;
  • 资源开销: 每个线程需要独立的栈空间,通常为 MB 级别,大量的线程会导致内核消耗过高;
  • 抢占式执行: 线程可以在任意时刻被操作系统暂停,转而执行其他线程,因此需要同步机制(如锁)来保证线程安全;
  • 共享内存: 同一进程内的线程共享内存空间,便于数据共享,但也容易引发竞态条件和死锁;
  • 阻塞操作: 当线程执行阻塞操作(如 IO、休眠)时,整个线程会被挂起,占用系统资源;
Thread thread = new Thread(() -> {
    // 处理逻辑
});
thread.start();
1.2 适用场景
  • CPU 密集型任务:多核 CPU 上的并行计算,充分利用多核优势;
  • 需要真正并行的场景:如科学计算、图像处理等需要同时执行多个任务的场景;

2 协程的并发模型

2.1 核心特点
  • 用户级调度: 协程由编程语言或框架(如 Kotlin 协程库)管理,调度在用户态完成,无需内核介入,开销极低;
  • 资源开销: 轻量级,单个协程的栈空间通常只有 KB 级别,一个线程可以运行数千甚至数百万个协程,创建和切换协程的开销极小;
  • 协作式执行: 协程只有在遇到 suspend 函数时才会主动让出控制权,不会被强制中断,因此无需锁机制即可实现线程安全;
  • 非阻塞操作: 协程的 suspend 函数在挂起时不会阻塞底层线程,线程可以继续执行其他协程;
  • 简化异步代码,避免回调地狱;
  • 结构化生命周期管理: 协程作用域(如 viewModelScope)自动取消所有子协程,防止泄漏;
val scope = CoroutineScope(Dispatchers.IO)
for (i in 1..10) {
    scope.launch {
        println("Task $i executed by ${Thread.currentThread().name}")
        delay(1000) // 非阻塞延迟,不占用线程
    }
}
delay(2000) // 等待所有协程完成

// 回调地狱
api.fetchUser { user ->
    api.fetchProfile(user) { user ->
        api.fetchDetails(profile) { detail ->
            updateUI(details)
        }
    }
}

// 协程(顺序执行)
viewModelScope.launch {
    val user = api.fetchUser() // 挂起函数
    val profile = api.fetchProfile(user)
    val details = api.fetchDetails(profile)
    updataUI(details)
}

结构化并发:

  • 作用域(CoroutineScope)
    • 定义:每个协程必须在特定的作用域内启动,作用域负责管理其生命周期;
    • 生命周期绑定:作用域通常与组件(如 ActivityViewModel)的生命周期绑定,确保组件销毁时自动取消所有关联的协程;
    • 常见作用域:
      • viewModelScope:与 ViewModel 生命周期绑定;
      • lifecycleScope:与 Activity/Fragment 生命周期绑定;
      • 自定义作用域:通过 CoroutineScope(context) 创建;
  • 父子协程关系:
    • 层次结构:协程之间形成父子关系,父协程取消时,所有子协程自动取消
parentScope.launch {
    launch {
        delay(1000)
        println("Child 1")
    }
    launch {
        delay(2000)
        println("Child 2")
        println("Child 2")
    }
}
2.2 适用场景
  • IO 密集型任务:如网络请求、文件操作,协程可以在等待 IO 时释放线程资源;
  • 高并发场景:需要处理大量并发连接的服务器(如 Web 服务器、消息队列);
2.3 总结

协程和线程

3 协程的适用场景

场景 协程的优势
网络请求 避免阻塞主线程,简化异步回调
数据库操作 结合 Room 的协程支持,实现流畅的数据库访问
文件 I/O 通过 Dispatchers.IO 高效调度
并发任务 使用 aync/await 并行执行任务并合并结果
UI 交互 在主线程安全更新 UI,避免 ANR

4 协程的关键组件

CoroutineScope 作用
CoroutineScope 定义协程作用域,管理生命周期(如 ViewModelScopelifecycleScope
Dispatchers 指定协程运行的线程(如 MainIODefault
launch 启动一个不返回结果的协程
async/await 启动一个返回 Deferred 结果的协程,通过 await() 获取结果
suspend 函数 标记可挂起的函数,只能在协程或其他挂起函数中调用

5 总结

协程是 Kotlin 异步编程的终极解决方案,其核心优势在于:

  • 轻量高效:支持大规模并发,资源消耗极低;
  • 非阻塞挂起:最大化线程利用率,避免资源浪费;
  • 结构化并发:通过作用域自动管理生命周期,减少泄漏风险;
  • 代码简洁:以同步风格编写异步代码,告别回调地狱;
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐