本系列专栏 #Kotlin协程
前言
前面文章我们介绍了挂起函数,协程借助挂起函数可以以同步的方式写出异步的代码,算是协程最大的亮点。本篇文章将介绍协程的另一个重大特性:结构化并发。
正文
什么是结构化并发,简单来说就是带有结构和层级的并发。
父子协程
在Java中我们知道想并发编程就使用多线程,但是线程和线程之间却是没有父子关系的,而协程可以做一样的并发编程,这些协程却是有父子关系的。
说起来可能不好理解,我们直接看个例子:
fun main() = runBlocking { val parentJob: Job var job1: Job? = null var job2: Job? = null var job3: Job? = null parentJob = launch { job1 = launch { delay(1000L) } job2 = launch { delay(3000L) } job3 = launch { delay(5000L) } } delay(500L) parentJob.children.forEachIndexed { index, job -> when (index) { 0 -> println("job1 === job is ${job1 === job}") 1 -> println("job2 === job is ${job2 === job}") 2 -> println("job3 === job is ${job3 === job}") } } parentJob.join() // 这里会挂起大约5秒钟 logX("Process end!") }
在代码中我们创建了3个Job分别是job1,job2和job3,然后有个parentJob,我们在parentJob中再次启动3个协程,然后最神奇的地方在下面的打印,我们取出parentJob的children中的job对象,来和前面job1、job2和job3比较会发现是同一个对象。
这也就说明job1、job2和job3是parnetJob的children,也就是说使用launch创建出来的协程,是存在父子关系的。
结构化
我们来看一下Job的代码:
public val children: Sequence<Job>
public fun attachChild(child: ChildJob): ChildHandle
可以看到每个Job对象都会有一个children属性,它的类型是Sequence,是一个惰性集合,那么我们就可以用一个简单的图来说明一下上面4个Job之间的关系:

而这个父子协程的关系就可以构成线程所不具备的结构化,我们也注意了前面代码中parentJob.join()会将代码挂起大约5s,而这个5s就是job3执行的时间,所以这就说明只有当其子协程都执行完毕后,parentJob才执行完成。
这种关系是线程中不存在的,比如我主线程开启子线程A,子线程A中再开启子线程B,这时子线程A运行完就结束了,不会和A和C有任何关系。
结构化取消
而这种有层次和结构的协程关系,有个非常重要的使用点,就是:结构化取消。
这个在Android开发中至关重要,比如我们使用MVVM架构,我们的逻辑都写在ViewModel中,而ViewModel会在页面销毁后销毁,这时我们使用ViewModel的协程范围即ViewModelScope来启动协程,在协程中做一些操作,不管这个操作调用得多复杂,当调用ViewModelScope.cancel()时把最外面的父协程取消掉,里面所有的子协程业务都会取消,会减少内存泄漏的风险。
比如下面代码:
fun main() = runBlocking { val parentJob: Job var job1: Job? = null var job2: Job? = null var job3: Job? = null parentJob = launch { job1 = launch { logX("Job1 start!") delay(1000L) logX("Job1 done!") // ①,不会执行 } job2 = launch { logX("Job2 start!") delay(3000L) logX("Job2 done!") // ②,不会执行 } job3 = launch { logX("Job3 start!") delay(5000L) logX("Job3 done!")// ③,不会执行 } } delay(500L) parentJob.cancel() // 变化在这里 logX("Process end!") }
这里还是一个parentJob和它的3个子协程,当我们执行父协程的cancel()方法时,其子协程也都会取消,这就太方便了。下图有个动图来表示一下:

总结
协程的结构化并发意思就是带有结构和层次的并发,而这个层次指的就是协程可以存在父子关系,取消父协程,就会取消其所有子协程。
评论(0)