抽丝剥茧聊Kotlin协程之Job初体验

简介: 抽丝剥茧聊Kotlin协程之Job初体验

image.png

1.前言



如果要我拿现实中的一事物与Kotlin协程中的Job做一个类比,那么我会把Job比作成海洋中的冰山。自由漂浮的冰山约有90%体积沉在海水表面下,因此看着浮在水面上的形状并猜不出水下的形状。与冰山一样,Job提供给开发者的功能非常简单,但是在协程框架内部Job却做了大量的工作。至关重要的是,如果开发者不去深入了解Job内部的实现机制,那么在使用协程的过程中,他就犹如开着船与冰山擦肩而过的船长,随时有可能面临系统崩溃的风险。如果你的项目中正在使用协程,如果你想享受协程编程带来的便利的同时又想保证程序的健壮性。那么深入理解Job的内部机制,会让你在遇到协程问题时,更从容,更游刃有余。


为了检验各位读者对协程Job的了解程度,我设计了两段代码,请问哪个Case “CancelJobActivity job2 finished”语句会被打印出来?


程序一:

private fun case1() {
    val scope = MainScope()
    scope.launch(Job()) {
        launch {
            delay(2000L)
            println("CancelJobActivity job1 finished")
            scope.cancel()
        }
        launch {
            delay(3000L)
            println("CancelJobActivity job2 finished")
        }
    }
}


程序二:


private fun case2() {
    val scope = MainScope()
    scope.launch {
        launch {
            delay(2000L)
            println("CancelJobActivity job1 finished")
            scope.cancel()
        }
        launch {
            delay(3000L)
            println("CancelJobActivity job2 finished")
        }
    }
}


上述两段代码的功能是:通过MainScope启动一个协程,在该协程中启动两个子协程。子协程1在delay 2s后打印语句并取消MainScope启动的协程,子协程2在delay 3s后打印语句。我们的期望是,子协程1在调用scope.cancel方法后,子协程2不会输出语句。程序二如我们所愿,但是程序一在3s后仍然输出了。显然程序一的结果不被我们接受。它们唯一的区别就是在scope.launch处是否有Job()参数。


为什么launch()方法增加Job()参数,就无法取消掉协程呢?要搞懂这个问题,就必须先搞懂,父子协程中的数据结构。引用Google官方公开的图片,我们可以看到,这是典型的树数据结构。


image.png

2. 原因分析


  1. 根据MainScope源码,我们知道scope对应的Job类型是SupervisorJob。
  2. launch方法创建的协程本身也是Job类型。而且它与启动该协程的CoroutineContext[Job]形成父子关系。
  3. launch(Job())根据CoroutineContext的plus方法,会用新的newJob代替SupervisorJob。


public fun MainScope(): CoroutineScope 
= ContextScope(SupervisorJob() + Dispatchers.Main)


  1. CoroutineScope.cancel方法,正是coroutineContext[Job]对应的Job cancel的。
public fun CoroutineScope.cancel(cause: CancellationException? = null) {
    val job = coroutineContext[Job] ?: error("Scope cannot be cancelled because it does not have a job: $this")
    job.cancel(cause)
}

程序二的关系图


image.png

image.png

image.png

image.png


从Job关系图,我们看出MainScope对应的SupervisorJob在程序一中,单独游离出来,并未与Job0、Job1、Job2形成有效的树形结构关系,所以通过scope.cancel()无法取消。


最后 Job相关的文章我构思了很久,由于Job比较复杂,一时间竟无从下手。本文权当一个起笔,Job原理与源码相结合的文章,后续会陆续更新。本文中的案例仅仅是Job难题中的冰山一角,cancel和异常处理机制,与Job树形结构关系图可以变化出很多种情况,但是如果能真正理解原理,处理起来也并不麻烦。下次我会从源码的角度,讲解Job的树形结构关系是如何建立起来的,以及Job的cancel机制是如何双向传播和异常处理机制是如何向上传播的。


相关文章
|
1月前
|
安全 Android开发 开发者
构建高效Android应用:Kotlin与协程的完美结合
【2月更文挑战第30天】在移动开发领域,性能优化和流畅的用户体验是关键。本文深入探讨了如何通过结合Kotlin语言和协程技术来提升Android应用的性能和响应能力。我们将分析Kotlin的优势,介绍协程的基本概念,并通过实际案例展示如何在应用中实现协程以简化异步编程,从而提供更加高效的解决方案。
|
1月前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin与协程的完美融合
【2月更文挑战第25天】 在移动开发领域,性能优化和应用响应性的提升是永恒的追求。随着Android Jetpack组件库的不断丰富,Kotlin语言已经成为Android开发的首选。而Kotlin协程作为一种新的并发处理方案,它以轻量级线程的形式,为开发者提供了简洁高效的异步编程手段。本文将深入探讨Kotlin协程在Android应用中的实践运用,以及如何通过这种技术改善用户界面的流畅度和后台任务的处理能力,进而构建出更高效、更稳定的Android应用。
|
1月前
|
移动开发 调度 Android开发
构建高效Android应用:Kotlin与协程的完美结合
【2月更文挑战第21天】随着移动开发技术的不断进步,Android平台正寻求更高效、更简洁的编程解决方案。Kotlin作为一种现代编程语言,以其简洁性和对函数式编程的支持赢得了开发者的青睐。而协程作为处理异步任务的强大工具,在提升应用性能方面显示出巨大潜力。本文将深入探讨Kotlin语言和协程技术如何相辅相成,帮助开发者构建更加流畅和高效的Android应用。
|
1月前
|
API 数据库 Android开发
构建高效安卓应用:Kotlin与协程的完美融合
【2月更文挑战第20天】在移动开发领域,性能优化和资源管理始终是开发者关注的焦点。随着Kotlin语言在Android平台的普及,协程作为其核心特性之一,提供了一种全新的异步编程范式。本文将深入探讨如何通过Kotlin协程提升安卓应用的性能,减少内存消耗,并实现流畅的用户体验。我们将分析协程的原理,展示其在实际应用中的效能,并提供实践指南,帮助开发者掌握这一强有力的工具。
15 0
|
1月前
|
安全 Java Android开发
构建高效Android应用:Kotlin与协程的完美融合
【2月更文挑战第15天】随着移动开发技术的不断进步,Android平台的开发者寻求更高效的编程解决方案以提升应用性能和用户体验。Kotlin作为官方推荐的开发语言,以其简洁性和功能安全性受到青睐。而协程,作为一种轻量级的线程管理机制,在异步编程和网络请求等方面展现出巨大潜力。本文将深入探讨Kotlin语言结合协程如何优化Android应用的性能,包括提高响应性、简化异步代码结构以及减少资源消耗等方面,旨在为开发者提供实战指南,帮助他们构建更加流畅和高效的Android应用。
|
6月前
|
安全 调度 数据库
Kotlin 学习笔记(五)—— 协程的基础知识,面试官的最爱了~(下)
Kotlin 学习笔记(五)—— 协程的基础知识,面试官的最爱了~(下)
43 0
|
6月前
|
Java Go Android开发
Kotlin 学习笔记(五)—— 协程的基础知识,面试官的最爱了~(上)
Kotlin 学习笔记(五)—— 协程的基础知识,面试官的最爱了~(上)
50 0
|
Java
Kotlin从入门到放弃(三)——协程
引言 这篇主要是将以下kotlin里面的协程,当然这个概念已经随着kotlin的文档被广泛得知了,不过还是用大量代码记录一下吧 一、概念    Coroutine,翻译为协程,意思为各个子任务程协作运行。
2218 0
|
25天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。