GlobalScope 与 runBlocking
GlobalScope:全局协程作用域
GlobalScope 是 Kotlin 协程库中预定义的全局协程作用域,其生命周期与整个应用程序一致。使用 GlobalScope 启动的协程具有以下特点:
- 生命周期独立:协程不会绑定到任何特定的组件(如 Activity 或 Fragment),即使组件销毁,协程仍会继续执行。
- 谨慎使用:容易造成内存泄漏或资源浪费,通常仅用于顶级长时间运行的任务(如日志上报、心跳检测等)。
基本用法
GlobalScope.launch {
// 在后台线程执行耗时操作
delay(1000L)
println("GlobalScope 协程执行完毕")
}
runBlocking:阻塞式协程构建器
runBlocking 是一个特殊的协程构建器,它会阻塞当前线程直到其内部所有协程执行完毕。主要用途包括:
- 测试环境:在单元测试中保证协程完成。
- 主函数:在
main()中启动协程程序。 - 桥接阻塞与非阻塞代码:临时将非阻塞协程代码嵌入传统阻塞调用链。
基本用法
fun main() = runBlocking {
// 主线程会在此阻塞
launch {
delay(1000L)
println("runBlocking 内部协程")
}
println("主线程继续执行")
}
// 输出顺序:
// 主线程继续执行
// runBlocking 内部协程
对比与最佳实践
| 特性 | GlobalScope | runBlocking |
|---|---|---|
| 线程行为 | 非阻塞(默认调度器为 Dispatchers.Default) | 阻塞当前线程 |
| 生命周期 | 全局作用域,需手动取消 | 随代码块结束自动取消 |
| 典型场景 | 应用级后台任务 | 测试、main() 函数或临时阻塞调用 |
最佳实践建议
- 避免滥用
GlobalScope:优先使用自定义的CoroutineScope(如viewModelScope或lifecycleScope)。 - 替代方案:在 Android 中,使用
lifecycleScope或viewModelScope替代GlobalScope。 runBlocking限制:禁止在 UI 线程或协程内部使用runBlocking,否则可能导致死锁。
示例:合理使用自定义作用域
// 自定义作用域示例
class MyComponent {
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
fun doWork() {
scope.launch {
// 安全的协程操作
}
}
fun destroy() {
scope.cancel() // 避免内存泄漏
}
}
⚠️ 注意:在 Android 中,直接使用
GlobalScope.launch可能导致 Activity 销毁后协程继续持有 View 引用,引发内存泄漏。
