协程是在线程上调度执行的任务单元,执行时可以“让出线程资源”,实现非阻塞式异步处理。
协程最核心的机制是"suspend"挂起,把"运行状态"保存起来,线程可以干别的,稍后再恢复运行协程
一、协程的基本组成
概念 | 说明 |
CoroutineScope | 协程作用域,管理协程生命周期 |
launch | 启动一个协程,返回job,不带结果 |
async | 启动协程兵返回结果,返回Deferred |
suspend | 声明一个挂起函数,可以暂停协程执行 |
Dispatcher | 控制协程在哪个线程或线程池中执行 |
Job/Deferred | 协程句柄,控制协程的取消/完成状态 |
runBlocking 阻塞主线程,直到其内部协程全部完成。只适用于main函数或测试场景。
二、协程执行的调度器
调度器 | 描述 | 用途 |
Dispatchers.Default | 后台线程池(CPU密集) | 排序、加密等重任务 |
Dispatchers.IO | IO线程池(无限扩展) | 网络、数据库操作 |
Dispatchers.Main | 主线程 | UI操作 |
Dispatchers.Main.immediate | 主线程 | 如果当前已经在主线程,立即执行协程(避免再入主线程消息队列),否则等同于Main。 |
Dispatchers.UnConfined | 不限制 | 一般不用 |
newSingleThreadContext | 自定义线程 | 调试、隔离操作 |
三、launch、async、withContext有什么区别?
方式 | 用途 | 返回值 | 用例 |
launch | 启动协程 | Job | 不关心结果、不等待完成 |
async | 启动协程+获取结果 | Deferred | 并发执行 |
withContext | 切换协程并执行 | suspend返回值 | 顺序执行,线程切换 |
//async()执行代码块必须在协程作用域中才能声明并执行 val userDeferred = async{getUser()} val orderDeffered = async{getOrders()} val user = userDeferred.await(); val orders = orderDeffered.await();
四、协程启动模式
启动模式 | 说明 |
DEFAULT | 立即调度执行 |
LAZY | 等调用.start()或.await()后才执行 |
ATOMIC | 无法在启动前取消 |
UNDISPATCHED | 立即执行直到第一个挂起点,不切线程 |
五、结构化并发与作用域设计
协程必须在 CoroutineScope中启动,决定了协程的生命周期是否可控
推荐的scope:
- viewModelScope(Jetpack ViewModel附带)
- lifecycleScope(Jetpack Lifecycle附带)
- coroutineScope()(局部作用域)
- supervisorScoe()(允许子协程独立失败)