🎯 协程基础
📖 协程入门
要使用协程,首先需要了解协程构建器。让我们来学习最基本的三个构建器!
💡 runBlocking
基本用法
import kotlinx.coroutines.*
fun main() = runBlocking { // 启动协程!
println("Hello")
delay(1000) // 等待1秒
println("World!")
}
特点
fun main() {
println("Before")
runBlocking {
delay(1000)
println("Inside coroutine")
}
println("After") // 等待协程结束
}
// Before
// (等待1秒)
// Inside coroutine
// After
注意:runBlocking 会阻塞当前线程!主要在测试或 main 函数中使用。
🚀 launch
启动异步任务
fun main() = runBlocking {
launch {
delay(1000)
println("Task 1")
}
launch {
delay(500)
println("Task 2")
}
println("Main")
}
// Main
// (500ms后) Task 2
// (1000ms后) Task 1
返回 Job
fun main() = runBlocking {
val job = launch {
repeat(5) { i ->
println("Working... $i")
delay(500)
}
}
delay(1300)
println("取消任务!")
job.cancel() // 取消任务
job.join() // 等待取消完成
}
管理多个任务
fun main() = runBlocking {
val jobs = List(5) { i ->
launch {
delay(1000L * i)
println("任务 $i 完成")
}
}
jobs.forEach { it.join() } // 等待所有任务
println("所有任务结束!")
}
⚡ async
接收返回结果
fun main() = runBlocking {
val deferred = async {
delay(1000)
return@async "结果值"
}
println("任务进行中...")
val result = deferred.await() // 等待结果
println("收到的值: $result")
}
launch vs async
fun main() = runBlocking {
// launch - 无返回结果
launch {
delay(1000)
println("launch 完成")
}
// async - 返回结果
val result = async {
delay(1000)
"async 完成"
}
println(result.await())
}
🎯 实战示例
并行处理
import kotlin.system.measureTimeMillis
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async { fetchData1() }
val two = async { fetchData2() }
println("结果: ${one.await()}, ${two.await()}")
}
println("耗时: ${time}ms") // ~1000ms (并行执行)
}
suspend fun fetchData1(): String {
delay(1000)
return "数据1"
}
suspend fun fetchData2(): String {
delay(1000)
return "数据2"
}
顺序 vs 并行
fun main() = runBlocking {
// ❌ 顺序执行(慢)
val time1 = measureTimeMillis {
val one = fetchData1()
val two = fetchData2()
println("$one, $two")
}
println("顺序: ${time1}ms") // ~2000ms
// ✅ 并行执行(快)
val time2 = measureTimeMillis {
val one = async { fetchData1() }
val two = async { fetchData2() }
println("${one.await()}, ${two.await()}")
}
println("并行: ${time2}ms") // ~1000ms
}
异常处理
fun main() = runBlocking {
val deferred = async {
delay(1000)
throw Exception("发生错误!")
}
try {
deferred.await()
} catch (e: Exception) {
println("捕获的错误: ${e.message}")
}
}
🔥 实用模式
超时
fun main() = runBlocking {
try {
withTimeout(1300) {
repeat(3) { i ->
println("任务 $i")
delay(500)
}
}
} catch (e: TimeoutCancellationException) {
println("超时!")
}
}
多个 API 调用
data class UserData(
val profile: String,
val posts: List<String>,
val friends: List<String>
)
suspend fun loadUserData(userId: String): UserData = coroutineScope {
val profile = async { fetchProfile(userId) }
val posts = async { fetchPosts(userId) }
val friends = async { fetchFriends(userId) }
UserData(
profile.await(),
posts.await(),
friends.await()
)
}
suspend fun fetchProfile(id: String): String {
delay(500)
return "Profile($id)"
}
suspend fun fetchPosts(id: String): List<String> {
delay(800)
return listOf("Post1", "Post2")
}
suspend fun fetchFriends(id: String): List<String> {
delay(600)
return listOf("Friend1", "Friend2")
}
重试逻辑
suspend fun <T> retryIO(
times: Int = 3,
delay: Long = 1000,
block: suspend () -> T
): T {
repeat(times - 1) { attempt ->
try {
return block()
} catch (e: Exception) {
println("尝试 ${attempt + 1} 失败")
delay(delay)
}
}
return block() // 最后一次尝试
}
fun main() = runBlocking {
val result = retryIO(times = 3) {
fetchDataFromAPI()
}
println(result)
}
var attempt = 0
suspend fun fetchDataFromAPI(): String {
attempt++
if (attempt < 3) {
throw Exception("网络错误")
}
return "成功!"
}
🛠️ coroutineScope
结构化并发
suspend fun doWork() = coroutineScope {
launch {
delay(1000)
println("任务 1")
}
launch {
delay(2000)
println("任务 2")
}
println("所有任务启动")
// 等待所有子任务结束
}
fun main() = runBlocking {
doWork()
println("完成!")
}
异常传播
suspend fun riskyWork() = coroutineScope {
launch {
delay(500)
throw Exception("错误!")
}
launch {
delay(1000)
println("这段代码不会执行")
}
}
fun main() = runBlocking {
try {
riskyWork()
} catch (e: Exception) {
println("捕获错误: ${e.message}")
}
}
🤔 常见问题
Q1. launch 和 async 的区别是什么?
A: 是否返回结果!
fun main() = runBlocking {
// launch - 不需要结果
launch {
println("简单任务")
}
// async - 需要结果
val result = async {
"要返回的值"
}
println(result.await())
}
Q2. join() 和 await() 的区别是什么?
A: join 等待完成,await 等待结果!
fun main() = runBlocking {
val job = launch {
delay(1000)
}
job.join() // 只等待完成
val deferred = async {
delay(1000)
"结果"
}
val result = deferred.await() // 等待结果
}
Q3. 协程会自动取消吗?
A: 父协程取消时,子协程也会取消!
fun main() = runBlocking {
val parent = launch {
val child = launch {
repeat(10) {
println("子任务 $it")
delay(500)
}
}
delay(1300)
println("父任务完成")
}
delay(2000)
parent.cancel() // 子协程也会一起取消
}
🎬 结语
我们已经掌握了协程的基本 构建器!
核心总结:
✅ runBlocking - 用于测试/main函数
✅ launch - 不需要返回结果的任务
✅ async - 接收返回结果
✅ coroutineScope - 结构化并发
✅ 通过并行处理提升性能
下一步:在 suspend 函数 中深入了解挂起函数!