16 | Job:协程也有生命周期吗?
Job 生命周期
- 深入了解
- 翻译
- 解释
- 总结
Kotlin协程的Job是协程的句柄,通过它暴露的API可以实现协程的生命周期管理和结构化并发。本文从使用的角度入手,介绍了Job的功能和用法,为读者提供了对Job的清晰认知。通过示例代码和详细解释,展示了Job的生命周期、状态查询、操控和等待状态等API的使用方法,以及如何监听协程结束事件。同时,通过对Job源代码的分析,读者可以更好地理解其内部实现。文章还介绍了Deferred接口,它继承自Job,提供了await()方法用于获取协程的执行结果。此外,文章还探讨了Job与结构化并发的关系,强调了协程的父子关系和结构化并发的重要性。通过具体的例子和代码分析,读者可以更好地理解协程的结构化并发特点。除此之外,作者还分享了学习协程的方法论,包括横向对比、建立思维模型和纵向深入,为读者提供了学习协程的有效途径。整体而言,本文为读者提供了全面的Job知识,帮助他们更好地理解和应用Kotlin协程中的Job对象。
《朱涛 · Kotlin 编程第一课》,新⼈⾸单¥59
全部留言(27)
- 最新
- 精选
- 面无表情的生鱼片思考题: 代码的执行结果是: > First coroutine start! > First coroutine end! > Process end! 可见 job2 的代码块并没有被执行。 分析原因: 分别打印出 job2 在 job2.join() 前后的状态: job2 before join: isActive === false job2 before join: isCancelled === true job2 before join: isCompleted === false // job2.join() job2 after join: isActive === false job2 after join: isCancelled === true job2 after join: isCompleted === true 可见 job2 创建后并没有被激活。 val job2 = launch(job) {} 这一行代码指示 job2 将运行在 job 的 CoroutineContext 之下, 而之前的代码 job.join() 时 job 已经执行完毕了,根据协程结构化的特性,job2 在创建后不会被激活,并且标记为Cancelled,然后执行 job2 时,发现 job2 未被激活,并且已经被取消,则不会执行 job2 的代码块,但是会将 job2 标记为 Completed
作者回复: 很棒的分析!
2022-02-18334 - 没名儿看了大家的留言有个疑点 ----很多异步任务之间都是没有互相依赖的,这样的代码结合挂起函数后,再通过 async 并发来执行,是可以大大提升代码运行效率的。---- ----如你所说,存在依赖关系的时候,我们就可以挂起函数与async结合了。----- 到底是存在依赖关系用async还是不存在依赖关系用async呢?
作者回复: “如你所说,存在依赖关系的时候,我们就可以挂起函数与async结合了。” 这句话确实有歧义,这里的语境是:如果B任务依赖A的结果,C任务跟A、B没有关系,我们就可以这样做: ``` // 伪代码 runBlocking { val resultB = async { val temp = taskA() taskB(temp) } val resultC = async { taskC() } } ``` 总结就是:如果存在依赖关系,就直接用挂起函数串联;如果没有依赖关系,就可以用async并联。
2022-03-1711 - 白乾涛思考题针对性不强。 因为思考题考察的知识点是 CoroutineContext 上下文,而这一部分是下一节课的内容。
作者回复: 本质还是“生命周期”、“结构化并发”哈,当然,本质还是CoroutineContext,这不刚好引出下节课嘛~
2022-02-236 - 魏全运思考题结果: First coroutine start! First coroutine end! Process end! 没有执行job2的原因是,它的launch中传入了job 作为coroutinecontext,而它已经是complete 状态了,所以不会再执行job2的block 而是直接执行了job2的join ,然后结束。
作者回复: 分析的不错。
2022-02-186 - 原仲代码片段14 中的执行流程 val result1 = async { getResult1() } val result2 = async { getResult2() } val result3 = async { getResult3() } //调用时机在这 results = listOf(result1.await(), result2.await(), result3.await()) 用作者的思维模型,相当于三个钓鱼杆同时拉杆 val result1 = async { getResult1() } //调用时机 result1.await() val result2 = async { getResult2() } //调用时机 result2.await() val result3 = async { getResult3() } //调用时机 result3.await() 用作者的思维模型,相当于三个钓鱼杆依次拉杆
作者回复: 赞!
2022-05-1422 - 20220106代码段10中【delay(500L)】这一句影响了什么呀?不加的话后边的日志就不打印了
作者回复: 它的作用是等待:job1/2/3对应的协程能够启动。
2022-04-1322 - Gavin"First coroutine start!" "First coroutine end!" "Process end!" 通过源码可知launch中传入的CoroutineContext会作为parentJob,而job2的parentJob为job,job协程已经处于completed状态,故不执行job2直接跳过
作者回复: 没错~
2022-02-232 - 20220106这里 await() 后面的代码,虽然看起来是阻塞了,但它只是执行流程被挂起和恢复的一种表现。而且如果你仔细思考的话,你会发现上面这个动图,同样也描述了之前 job.join() 的行为模式,在协程执行完毕之前,后面的协程代码都被暂时挂起了,等到协程执行完毕,才有机会继续执行。 ——”在协程执行完毕之前“这里的协程指的父级协程,“后面的协程代码都被暂时挂起了“这里的协程代码指的子级协程代码部份。也就是说:如果子级自己有挂起操作,那么子级的代码会被暂时挂起,直到父级的协程代码执行完毕之后再继续执行子级协程代码(前提是父级没有挂起延迟之类的操作)。
作者回复: 是这个意思。
2022-04-141 - dawnfun main() = runBlocking { val job = launch { logX("Coroutine start!") delay(1000L) logX("Coroutine end!") } job.log() delay(500) job.cancel() job.log() delay(1) //延时1ms job.log() delay(2000) logX("Process end!") } 为什么取消后输出延时1ms输出job的isCompleted会有false变为true
作者回复: 单纯只是因为Job的状态变更没那么及时而已。
2022-03-301 - 张国庆最后问题应该是按顺序打印
作者回复: 你可以试着运行一下看看效果,不要忽略了“launch(job) {}”当中的job参数哦!
2022-02-181