跳转到内容

Kotlin协程基础

来自代码酷

Kotlin协程基础[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

Kotlin协程是一种轻量级的并发编程框架,用于简化异步和非阻塞代码的编写。协程允许开发者以顺序的方式编写异步代码,同时避免传统回调或线程带来的复杂性。它们是Kotlin语言的核心特性之一,特别适合处理I/O密集型或CPU密集型任务。

协程的核心特点包括:

  • 轻量级:协程的创建和切换成本远低于线程。
  • 结构化并发:通过作用域(CoroutineScope)管理协程的生命周期,避免资源泄漏。
  • 挂起函数(Suspend Function):允许协程在等待结果时暂停执行,而不阻塞线程。

基本概念[编辑 | 编辑源代码]

协程构建器[编辑 | 编辑源代码]

Kotlin提供了几种协程构建器来启动协程:

  • launch:启动一个不返回结果的协程(适合“发后即忘”任务)。
  • async:启动一个返回`Deferred`结果的协程(可通过`await`获取结果)。
  • runBlocking:阻塞当前线程直到协程完成(主要用于测试或主函数)。
import kotlinx.coroutines.*

fun main() = runBlocking {
    // 使用 launch
    val job = launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join() // 等待协程完成

    // 使用 async
    val deferred = async {
        delay(1000L)
        "Result"
    }
    println("Waiting...")
    println(deferred.await()) // 输出: Result
}

输出:

Hello,
World!
Waiting...
Result

挂起函数[编辑 | 编辑源代码]

挂起函数是协程的核心,使用`suspend`关键字标记。它们只能在协程或其他挂起函数中调用。

suspend fun fetchData(): String {
    delay(1000L) // 模拟网络请求
    return "Data loaded"
}

fun main() = runBlocking {
    val data = fetchData()
    println(data) // 输出: Data loaded
}

协程上下文与调度器[编辑 | 编辑源代码]

协程上下文(CoroutineContext)决定协程运行的线程或线程池。常见的调度器:

  • Dispatchers.Default:适合CPU密集型任务。
  • Dispatchers.IO:适合I/O操作。
  • Dispatchers.Main(Android):在主线程运行。
fun main() = runBlocking {
    launch(Dispatchers.Default) {
        println("Running on Default: ${Thread.currentThread().name}")
    }
    launch(Dispatchers.IO) {
        println("Running on IO: ${Thread.currentThread().name}")
    }
}

输出(可能):

Running on Default: DefaultDispatcher-worker-1
Running on IO: DefaultDispatcher-worker-2

实际案例[编辑 | 编辑源代码]

并发网络请求[编辑 | 编辑源代码]

以下示例展示如何使用协程并发执行多个网络请求:

suspend fun fetchUser(id: Int): String {
    delay(500L) // 模拟网络延迟
    return "User$id"
}

fun main() = runBlocking {
    val time = measureTimeMillis {
        val user1 = async { fetchUser(1) }
        val user2 = async { fetchUser(2) }
        println("${user1.await()} and ${user2.await()}") // 并发执行
    }
    println("Completed in $time ms") // 约500ms而非1000ms
}

输出:

User1 and User2
Completed in 503 ms

协程与UI更新(Android示例)[编辑 | 编辑源代码]

在Android中,协程可用于避免主线程阻塞:

// 假设在Activity中
fun loadData() {
    lifecycleScope.launch {
        val data = withContext(Dispatchers.IO) { // 切换到IO线程
            fetchFromNetwork() // 耗时操作
        }
        updateUI(data) // 自动切换回主线程
    }
}

协程生命周期[编辑 | 编辑源代码]

协程的生命周期通过`Job`对象管理,支持取消和状态监听:

stateDiagram [*] --> New New --> Active: start() Active --> Completing: 完成中 Completing --> Completed: 完成 Active --> Cancelling: cancel() Cancelling --> Cancelled: 完成 Cancelled --> [*] Completed --> [*]

示例代码:

fun main() = runBlocking {
    val job = launch {
        try {
            repeat(1000) { i ->
                println("Working $i")
                delay(100L)
            }
        } finally {
            println("Cleanup resources")
        }
    }
    delay(250L)
    job.cancelAndJoin() // 取消协程并等待结束
}

输出:

Working 0
Working 1
Working 2
Cleanup resources

常见问题[编辑 | 编辑源代码]

协程与线程的区别[编辑 | 编辑源代码]

  • 协程是逻辑工作单元,线程是系统资源。
  • 一个线程可运行多个协程(协程挂起时释放线程资源)。

结构化并发[编辑 | 编辑源代码]

通过`coroutineScope`或`supervisorScope`创建子作用域,子协程失败时父协程可自动取消:

fun main() = runBlocking {
    coroutineScope {
        launch {
            delay(500L)
            throw RuntimeException("Failed!")
        }
        launch {
            delay(1000L)
            println("This won't execute")
        }
    }
}

总结[编辑 | 编辑源代码]

Kotlin协程通过挂起函数和结构化并发简化了异步编程。关键要点:

  • 使用`launch`/`async`启动协程,`suspend`定义挂起函数。
  • 通过调度器(如`Dispatchers.IO`)控制线程行为。
  • 通过`Job`管理生命周期,避免资源泄漏。