在 Kotlin 协程中,主要有三种核心启动方式,每种方式都有其特定的使用场景和特点:
一、协程启动方式
二、启动方式详解
1. launch
- 启动不需要返回结果的协程
val job = CoroutineScope(Dispatchers.IO).launch {
// 执行异步操作
delay(1000)
println("任务完成")
}
// 控制协程生命周期
job.cancel() // 取消协程
job.join() // 等待协程完成
特点:
返回
Job
对象(无结果值)Fire-and-forget 模式(发后即忘)
适用于后台任务(日志上传、缓存清理等)
2. async
- 启动需要返回结果的协程
val deferred = CoroutineScope(Dispatchers.Default).async {
// 执行计算任务
delay(1000)
42 // 返回计算结果
}
// 获取结果(会挂起当前协程)
val result = deferred.await()
println("计算结果: $result")
特点:
返回
Deferred<T>
对象(继承自 Job)通过
await()
获取结果(会挂起当前协程)支持并行任务:
val result1 = async { fetchDataFromAPI1() } val result2 = async { fetchDataFromAPI2() } val combined = result1.await() + result2.await()
3. runBlocking
- 阻塞式启动协程
fun main() {
runBlocking {
// 在阻塞协程中执行
delay(1000)
println("主线程阻塞1秒")
}
println("程序继续执行")
}
特点:
阻塞当前线程直到协程完成
主要用于测试、main函数和桥接阻塞代码
禁止在UI线程使用(会导致ANR)
三、启动参数配置
所有启动函数都支持 start
参数:
launch(start = CoroutineStart.LAZY) {
// 延迟启动的协程
}
启动模式 | 行为描述 | 使用场景 |
---|---|---|
DEFAULT |
立即调度执行(默认) | 大多数情况 |
LAZY |
仅在需要时启动(手动调用start/join/await触发) | 条件触发任务 |
ATOMIC |
原子性启动(不可取消) | 关键初始化操作 |
UNDISPATCHED |
立即在当前线程执行首段代码 | 优化上下文切换 |
四、启动方式对比表
特性 | launch |
async |
runBlocking |
---|---|---|---|
返回类型 | Job |
Deferred<T> |
T (泛型结果) |
是否阻塞线程 | 非阻塞 | 非阻塞 | 阻塞当前线程 |
结果获取 | 无返回值 | await() 获取结果 |
直接返回结果 |
异常处理 | 异常会传播到父协程 | 异常在await时抛出 | 异常直接抛出 |
适用场景 | 后台任务、事件触发 | 并行计算、结果聚合 | 测试、main函数、脚本 |
取消传播 | 通过Job控制 | 通过Deferred控制 | 不可取消 |
生命周期 | 随作用域结束自动取消 | 随作用域结束自动取消 | 执行完成后自动结束 |
五、实践使用
网络请求组合:
suspend fun fetchCombinedData(): CombinedResult = coroutineScope { val user = async { api.getUser() } val posts = async { api.getPosts() } CombinedResult(user.await(), posts.await()) }
超时控制:
val result = withTimeoutOrNull(3000) { async { longRunningTask() }.await() } ?: fallbackValue
任务编排:
val job = launch { val step1 = async { doStep1() } val step2 = async { doStep2(step1.await()) } val step3 = async { doStep3(step2.await()) } processFinalResult(step3.await()) }
七、常见问题总结
Q:请解释Kotlin协程的启动方式及其区别?
A:
“Kotlin协程有三种核心启动方式:
1.
launch
- 任务执行器
返回
Job
对象,用于控制协程生命周期不返回结果,适用于'发后即忘'场景
示例:后台日志上传、定时清理任务
2.
async
- 结果获取器
返回
Deferred<T>
(继承Job),通过await()
获取结果支持并行任务组合,如并发网络请求
示例:同时获取用户资料和好友列表
3.
runBlocking
- 阻塞桥接器
阻塞当前线程直到协程完成
主要用于测试、main函数和桥接阻塞代码
禁止在Android主线程使用(会导致ANR)
关键区别:
维度 launch async runBlocking 返回值 无 有 有 阻塞性 非阻塞 非阻塞 阻塞 使用场景 后台任务 结果聚合 测试/main