Kotlin第八阶段学习内容详情
Kotlin 第八阶段学习内容详情:协程入门
本阶段目标是理解 Kotlin 协程的基础用法,能写出简单异步任务。协程内容比较重要,也比较容易一开始觉得抽象,所以本阶段只追求「能看懂、能写简单示例」,不急着深入底层原理。
建议用时:5-7 天。
阶段目标
- 知道协程解决什么问题。
- 能理解
suspend函数的含义。 - 能使用
runBlocking运行入门示例。 - 能使用
launch启动协程。 - 能使用
async和await获取异步结果。 - 初步理解
Dispatchers。 - 初步理解结构化并发。
学习前说明
在普通 Kotlin 项目中使用协程,需要添加 kotlinx-coroutines-core 依赖。Android 项目或部分模板可能已经配置好。
Gradle Kotlin DSL 示例:
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
}
如果你的项目版本不同,以项目已有配置为准。
第 1 天:协程是什么
1. 直观理解
协程可以帮助你写异步代码,比如:
- 模拟网络请求。
- 读取文件。
- 等待数据库返回。
- 同时执行多个耗时任务。
协程不是线程,但它可以让异步代码写起来像同步代码一样清楚。
2. 第一个协程示例
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
println("开始")
delay(1000)
println("结束")
}
delay(1000) 表示挂起 1000 ms,它不会像 Thread.sleep() 那样直接阻塞线程。
3. runBlocking
runBlocking 会创建一个协程作用域,并阻塞当前线程直到里面的协程执行完。它适合写学习示例和测试代码。
实际业务代码中不会到处写 runBlocking。
第 2 天:suspend 函数
1. 什么是 suspend
suspend 表示这个函数可以挂起。
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
suspend fun fetchUserName(): String {
delay(1000)
return "Alice"
}
fun main() = runBlocking {
val name = fetchUserName()
println(name)
}
2. suspend 函数在哪里调用
suspend 函数只能在协程中或另一个 suspend 函数中调用。
错误写法:
suspend fun fetchData(): String {
return "data"
}
fun main() {
fetchData() // 错误
}
正确写法:
import kotlinx.coroutines.runBlocking
suspend fun fetchData(): String {
return "data"
}
fun main() = runBlocking {
println(fetchData())
}
第 3 天:launch
1. 启动一个协程
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
launch {
delay(1000)
println("协程任务完成")
}
println("主流程继续")
}
2. 多个 launch
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
launch {
delay(1000)
println("任务 1 完成")
}
launch {
delay(500)
println("任务 2 完成")
}
println("等待任务完成")
}
launch 适合启动没有返回值的任务。
第 4 天:async 与 await
1. 获取异步结果
async 适合启动有返回值的任务。
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
suspend fun getPrice(): Int {
delay(1000)
return 100
}
suspend fun getCount(): Int {
delay(1000)
return 3
}
fun main() = runBlocking {
val priceDeferred = async { getPrice() }
val countDeferred = async { getCount() }
val total = priceDeferred.await() * countDeferred.await()
println("总价:$total")
}
2. 对比顺序执行
fun main() = runBlocking {
val price = getPrice()
val count = getCount()
println(price * count)
}
顺序执行大约需要 2 秒,并发执行大约需要 1 秒。
第 5 天:Dispatchers
1. Dispatchers 是什么
Dispatchers 用于指定协程运行在哪类线程上。
常见类型:
| Dispatcher | 常见用途 |
|---|---|
Dispatchers.Default |
CPU 计算任务 |
Dispatchers.IO |
文件、网络、数据库等 IO 任务 |
Dispatchers.Main |
Android 主线程 |
2. 示例
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
launch(Dispatchers.Default) {
println("执行计算任务")
}
launch(Dispatchers.IO) {
println("执行 IO 任务")
}
}
普通命令行项目里不一定有 Dispatchers.Main,Android 项目中更常见。
第 6 天:结构化并发入门
1. 父协程等待子协程
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
launch {
delay(500)
println("子任务完成")
}
println("父作用域中")
}
runBlocking 会等待里面启动的子协程完成。
2. coroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
suspend fun loadData() = coroutineScope {
launch {
delay(500)
println("加载用户")
}
launch {
delay(800)
println("加载订单")
}
}
fun main() = runBlocking {
loadData()
println("全部加载完成")
}
综合练习
练习 1:模拟网络请求
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
suspend fun fetchMessage(): String {
delay(1000)
return "请求成功"
}
fun main() = runBlocking {
println("开始请求")
val message = fetchMessage()
println(message)
}
练习 2:并发加载用户和订单
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
suspend fun fetchUser(): String {
delay(1000)
return "Alice"
}
suspend fun fetchOrders(): List<String> {
delay(1000)
return listOf("订单 1", "订单 2")
}
fun main() = runBlocking {
val userDeferred = async { fetchUser() }
val ordersDeferred = async { fetchOrders() }
val user = userDeferred.await()
val orders = ordersDeferred.await()
println("用户:$user")
println("订单:$orders")
}
练习 3:多个任务顺序对比
自己写两个版本:
- 版本 1:顺序调用 2 个
suspend函数。 - 版本 2:用
async并发调用 2 个suspend函数。
观察执行时间差异。
必须掌握清单
常见错误
1. 在普通函数中直接调用 suspend
suspend fun fetchData(): String = "data"
fun main() {
fetchData() // 错误
}
2. 用 launch 期待返回值
launch 不直接返回业务结果。如果需要结果,用 async。
3. 在学习示例之外滥用 runBlocking
runBlocking 适合示例和测试,不适合在业务代码中随手包一层。
阶段复盘问题
- 协程解决什么问题?
suspend是什么意思?launch和async有什么区别?await()的作用是什么?Dispatchers.IO适合什么任务?- 什么是结构化并发?

浙公网安备 33010602011771号