1. 协程构建器
1.1 launch与async构建器都用来启动新协程
- launch,返回一个Job并且不附带任何结果值
- async,返回一个Deferred,Deferred也是一个Job,可以使用.await()在一个延期的值上得到它的最终结果
launch与async的区别是一个没有返回值,一个有返回值
1.2 等待一个作业
- 如果使用launch,则使用join等待,如果使用async,则使用await等待
- 组合并发
join与async的区别是join没有返回值,async有返回值
2. 协程的启动模式
- DEFAULT:协程创建后,立即开始调度,在调度前如果协程被取消,其将直接进入取消响应的状态
- ATOMIC:协程创建后,立即开始调度,协程执行到第一个挂起点之前不响应取消
- LAZY:只有协程被需要时,包括主动调用协程的start、join、或者await等函数时才会开始调度,如果调度前就被取消,那么该协程将直接进入一场结束状态
- UNDISPATCHED:协程创建后立即在当前函数调用栈中执行,直到遇到第一个真正挂起的点。
3. 协程的作用域构建器
3.1 coroutineScope与runBlocking
- runBlocking是常规函数,而coroutineScope是挂起函数
- 它们都会等待其协程体以及所有子协程结束,主要区别在于runBlocking方法会阻塞当前线程来等待,而coroutineScope只是挂起,会释放底层线程用于其他用途。
3.2 coroutineScope与supervisorScope
- coroutineScope:一个协程失败了,所有其他兄弟协程也会被取消
- supervisorScope:一个协程失败了,不会影响其他兄弟协程
4. Job对象
- 对于每一个创建的协程(通过launch或者async),会返回一个Job实例,该实例是协程的唯一标识,并且负责管理协程的生命周期。
- 一个任务可以包含一些列状态:新创建(New)、活跃(Active)、完成中(Completing)、已完成(Completed)、取消中(Cancelling)和已取消(Cancelled)。虽然我们无法直接访问这些状态,但是我们可以访问Job的属性:isActive、isCancelled和isCompleted。
5. Job的生命周期
如果协程处于活跃状态,协程运行出错或者调用job.cancel()都会将当前任务置为取消中(isActive = false, isCancelled = true)。当所有的子协程都完成后,协程会进入已取消(Cancelled)状态,此时isCompleted = true.
6. 协程的取消
- 取消作用域会取消它的子协程。
- 被取消的子协程并不会影响其余兄弟协程。
- 协程通过抛出一个特殊的异常CancellationException来处理取消操作。
- 所有kotlinx.coroutines中的挂起函数(withContext、delay等)都是可取消的。
7. CPU密集型任务取消
-
isActive是一个可以被使用在CoroutineScope中的扩展属性,检查Job是否处于活跃状态
-
ensureActive(),如果job处于非活跃状态,这个方法会立即抛出异常
-
yield函数会检查所在协程的状态,如果已经取消,则抛出CancellationException予以响应。此外,它还会尝试出让线程的执行权,给其他协程提供执行机会。
8. 协程取消的副作用
- 在finally中释放资源
- use函数:该函数只能被实现了Closeable的对象使用,程序结束的时候会自动调用close方法,适合文件对象
9. 不能取消的任务
-
处于取消中状态的协程不能够挂起(运行不能取消的代码),当协程被取消后需要调用挂起函数,我们需要将清理任务的代码放置于NonCancellable CoroutineContext 中。
-
这样会挂起运行中的代码,并保持协程的取消中状态直到任务处理完成。
10. 超时任务
- 很多情况下取消一个协程的理由是它有可能超时。
- withTimeoutOrNull通过返回null来进行超时操作,从而替代抛出一个异常。
11. Cancel与CancelAndJoin的区别
为了实现结构化取消操作,我们可以使用cancel方法或者cancelAndJoin方法来取消协程。cancel方法是Job对象的方法,它会取消目标协程,并递归地取消所有子协程。cancelAndJoin方法是Job对象的扩展方法,它会先调用cancel方法,然后调用join方法,等待目标协程和所有子协程都完成。
执行cancel后,isCompleted为false
执行cancelAndJob后,isCompleted为true