KotlinKotlin-Coroutines

Kotlin-协程核心库分析-Job简述

2021-02-04  本文已影响0人  有腹肌的豌豆Z

Job是标准库中启动协程后返回的对象,代表着协程本次作业。我们可以判断协程是否结束,是否取消,是否完成并且可以取消当前协程以及嵌套子协程。
一个job 可以理解成他就是一个协程对象。这个job可以开始、取消、状态就监听等操作。

我们简单的看下面的代码如何获取job对象

fun main() {

    val job = GlobalScope.launch {

    }
    //协程是否存活   
    job.isActive
    //是否取消
    job.isCancelled
    //是否完成
    job.isCompleted
    //取消协程
    job.cancel()
    //(非懒启动模式的)启动协程
    job.start()
}

Job继承关系

首先我们注意一点:他继承Element证明他能被放入协程上下文中,且Key为Job。在标准库启动协程后Job对象将放入其上下文中
我们看先一个简单的示例代码:

fun log(msg: String) {
    println("[${Thread.currentThread().name}] ${msg}")
}

fun main() {

    val job = GlobalScope.launch {
        //获取当前的上下文
        val job = coroutineContext
        log("协程内部job:$job")

        val job2=launch {
            val job2=coroutineContext
            log("协程内部job2:$job2")
        }
        log("协程内部job2:$job2")
    }
    
    //协程返回的job和内部或者是同一对象
    log("协程外部的job:$job")
    TimeUnit.HOURS.sleep(1)
}

[main] 协程外部的job:StandaloneCoroutine{Active}@73c6c3b2
[DefaultDispatcher-worker-1] 协程内部job:[StandaloneCoroutine{Active}@73c6c3b2, DefaultDispatcher]
[DefaultDispatcher-worker-1] 协程内部job2:StandaloneCoroutine{Active}@749f0c36
[DefaultDispatcher-worker-2] 协程内部job2:[StandaloneCoroutine{Active}@749f0c36, DefaultDispatcher]

Job 状态

Job有三个暴露的函数用于判断其状态:

Demo说明:
fun main() {

    //启动一个懒启动 CoroutineStart.LAZY用说明isActive不一定
    val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
        //获取当前的上下文
        TimeUnit.MILLISECONDS.sleep(500)
        log("协程完成")
    }

    log("未启动协程之前的状态: isActive: [${job.isActive}]  isCompleted: [${job.isCompleted}]  isCancelled: [${job.isCancelled}] ")
    job.start()
    log("启动协程之后的状态: isActive: [${job.isActive}]  isCompleted: [${job.isCompleted}]  isCancelled: [${job.isCancelled}] ")
    TimeUnit.MILLISECONDS.sleep(600)
    log("启动协程完成之后的状态: isActive: [${job.isActive}]  isCompleted: [${job.isCompleted}]  isCancelled: [${job.isCancelled}] ")

    TimeUnit.HOURS.sleep(1)
}

[main] 未启动协程之前的状态: isActive: [false] isCompleted: [false] isCancelled: [false]
[main] 启动协程之后的状态: isActive: [true] isCompleted: [false] isCancelled: [false]
[DefaultDispatcher-worker-1] 协程完成
[main] 启动协程完成之后的状态: isActive: [true] isCompleted: [false] isCancelled: [false]

取消状态Demo:
suspend fun main() {

    //启动一个懒启动 CoroutineStart.LAZY用说明isActive不一定
    val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
        //获取当前的上下文
        TimeUnit.MILLISECONDS.sleep(500)
        log("协程完成")
    }

    log("未启动协程之前的状态: isActive: [${job.isActive}]  isCompleted: [${job.isCompleted}]  isCancelled: [${job.isCancelled}] ")
    job.start()
    log("启动协程之后的状态: isActive: [${job.isActive}]  isCompleted: [${job.isCompleted}]  isCancelled: [${job.isCancelled}] ")
    job.cancel()
    log("启动协程取消之后的状态: isActive: [${job.isActive}]  isCompleted: [${job.isCompleted}]  isCancelled: [${job.isCancelled}] ")
    job.join()
    log("启动协程取消并且之后的状态: isActive: [${job.isActive}]  isCompleted: [${job.isCompleted}]  isCancelled: [${job.isCancelled}] ")

    TimeUnit.HOURS.sleep(1)
}

[main] 未启动协程之前的状态: isActive: [false] isCompleted: [false] isCancelled: [false]
[main] 启动协程之后的状态: isActive: [true] isCompleted: [false] isCancelled: [false]
[main] 启动协程取消之后的状态: isActive: [false] isCompleted: [false] isCancelled: [true]
[DefaultDispatcher-worker-1] 协程完成
[DefaultDispatcher-worker-1] 启动协程取消并且之后的状态: isActive: [false] isCompleted: [true] isCancelled: [true]

当然Job有自己内部的状态变化,然后这些内部的变化比较多,然后部分变化也就对应了我们isActive,isCompleted,isCancelled三个状态的数值。

简要的说明下内部的状态变化:

New 当我们创建一个协程并未启动时候就是出于New状态(使用CoroutineStart.LAZY方式时便可看到).
Active 当我们调用job.start函数的之后,且当前job没有执行完成
Cancelling当我们调用取消的时候立即进入此状态
Cancelled 最终取消任务完成
Completing当协程完成的时候需要等候子协程完成的状态
Completed 协程完成

Job 一些常用方法或者属性

单独说下 invokeOnCompletion函数:
invokeOnCompletion函数用于监听其完成或者其取消状态,
参数一:onCancelling参数用于判断是否监听取消事件否则监听完成事件,
参数二:invokeImmediately参数主要用于监听已经完成协程时是否回调,如果为false 那么如果在添加监听事件时协程已经完成或取消那么将不会回调.

fun main() = runBlocking{

    val job = GlobalScope.launch {
    }

    job.join()
    job.invokeOnCompletion(onCancelling = false, invokeImmediately = false) {
        log("取消的回调"+it)
    }

    TimeUnit.SECONDS.sleep(10000)
    log("main 结束")
}

上面的例子中:
log("取消的回调"+it)永不执行

上一篇下一篇

猜你喜欢

热点阅读