推广

Kotlin-协程的取消关键技术分析

iseeyu2年前 (2024-02-21)推广128

image-20210615111549352

fun main() = runBlocking {
    val myJob = GlobalScope.launch {
        repeat(200) { i ->
            println("hello: $i")

            delay(500)

        }
    }

    delay(1100)
    println("hello world")

    myJob.cancel()
    myJob.join()


    println("welcome")
}

RUN> ??????

hello: 0
hello: 1
hello: 2
hello world
welcome

Process finished with exit code 0

image-20210615112101098

下面来瞅一下它的cancel()方法的说明:

image-20210615112244628

public fun cancel(cause: CancellationException? = null)
cause: CancellationException? = null 可空类型,默认值为null
Thrown by cancellable suspending functions if the Job of the coroutine is cancelled while it is suspending. It indicates normal cancellation of a coroutine. It is not printed to console/log by default uncaught exception handler. See CoroutineExceptionHandler
public actual typealias CancellationException = java.util.concurrent.CancellationException

image-20210615112533715

可以显示的指定一下这个参数,如下:

fun main() = runBlocking {
    val myJob = GlobalScope.launch {
        repeat(200) { i ->
            println("hello: $i")

            delay(500)

        }
    }

    delay(1100)
    println("hello world")

    myJob.cancel(CancellationException("just a try"))
    myJob.join()


    println("welcome")
}
myJob.cancel(CancellationException("just a try"))
myJob.join()
这俩一定是成对的出现,其中为啥一定得要调用join()
是因为Cancel调用之后其协程并不会立马就取消,
所以这个join0需要等待一下协程彻底取消

那既然这俩是需要成对来编写的,那有没有一种简化的方法能代替上面两句代码呢?答案是肯定的,如下:

fun main() = runBlocking {
    val myJob = GlobalScope.launch {
        repeat(200) { i ->
            println("hello: $i")

            delay(500)

        }
    }

    delay(1100)
    println("hello world")

    myJob.cancelAndJoin()


    println("welcome")
}
/**
Cancels the job and suspends the invoking coroutine until the cancelled job is complete.
This suspending function is cancellable and always checks for a cancellation of the invoking coroutine's Job. If the Job of the invoking coroutine is cancelled or completed when this suspending function is invoked or while it is suspended, this function throws CancellationException.
In particular, it means that a parent coroutine invoking cancelAndJoin on a child coroutine that was started using launch(coroutineContext) { ... } builder throws CancellationException if the child had crashed, unless a non-standard CoroutineExceptionHandler is installed in the context.
This is a shortcut for the invocation of cancel followed by join.
*/
public suspend fun Job.cancelAndJoin() {
    cancel()
    return join()
}

取消任务并且挂起这个调用的协程直到取消的任务真正的执行完。

image-20210615115128324

kotlinx.coroutines包下的所有挂起函数都是可取消的,他们会检查协程的取消状态,当取消时就会抛出CancellationException异常。不过,如果协程正在处于某个计算过程当中,并且没有检查取消状态,那么它就是无法被取消的。”

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime

        var i = 0

        while (i < 20) {
            if (System.currentTimeMillis() >= nextPrintTime) {//CPU空转轮询
                println("job: I am sleeping ${i++}")
                nextPrintTime += 500L
            }
        }
    }

    delay(1300)
    println("hello world")

    job.cancelAndJoin()
    println("welcome")
}

RUN> ??????

job: I am sleeping 0
job: I am sleeping 1
job: I am sleeping 2
hello world
job: I am sleeping 3
job: I am sleeping 4
job: I am sleeping 5
job: I am sleeping 6
job: I am sleeping 7
job: I am sleeping 8
job: I am sleeping 9
job: I am sleeping 10
job: I am sleeping 11
job: I am sleeping 12
job: I am sleeping 13
job: I am sleeping 14
job: I am sleeping 15
job: I am sleeping 16
job: I am sleeping 17
job: I am sleeping 18
job: I am sleeping 19
welcome

Process finished with exit code 0

呃,居然协程木有取消成功,这是为啥呢?其实这里要论证的就是刚才的这个理论:

如果协程正在处于某个计算过程当中,并且没有检查取消状态,那么它就是无法被取消的

那怎么能让其正常取消呢?这里又得先来看一下理论:

image-20210615120019312

有两种方式可以让计算代码变为可取消的:

1、周期性地调用了一个挂起函数,该挂起函数会检测取消状态,比如说使用yield函数。

2、显示地检查取消状态。

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime

        var i = 0

        while (isActive) {
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I am sleeping ${i++}")
                nextPrintTime += 500L
            }
        }
    }

    delay(1300)
    println("hello world")

    job.cancelAndJoin()
    println("welcome")
}

RUN> ??????

job: I am sleeping 0
job: I am sleeping 1
job: I am sleeping 2
hello world
welcome

Process finished with exit code 0
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public val CoroutineScope.isActive: Boolean
    get() = coroutineContext[Job]?.isActive ?: true
// CoroutineScope的一个扩展属性

image-20210615115810054

第一个程序delay(500) 为什么可以被取消

delay(500)

image-20210615120458109

扫描二维码推送至手机访问。

版权声明:本文由西安泽虎代运营发布,如需转载请注明出处。

转载请注明出处https://0291.com.cn/post/57626.html

相关文章

删除旧内容是否影响网站排名。

删除旧内容是否影响网站排名。

这里有一个问题,垂直行业的内容资源库是有限的,我们不可能长期持续有价值的新内容长期输出,因此,seo人员开始研究“以旧换新”或者直接删除旧内容的策略。那么,SEO删除旧内容,对排名有影响吗?根据以往网站内容添加的经验,将通过如下内容,进一步说明: 1、算法更新:如果你长期跟踪百度SEO,你会发现在...

新手如何做好SEO。

新手如何做好SEO。

SEO优化汉译为搜索引擎优化。是一种方式:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。 第一、用户体验 一个网站的好坏全部在于用户体验,顾客觉得你这个网站信息够多、够相信、有价值百度自然会给你的网站加分。网站建设有很多需要注意的地方,比如网站关键词的布局设置,关键词的布局是一个网站...

短视频广告后期剪辑技巧

短视频广告后期剪辑技巧

  一、剪辑前期的创意准备 首先好的剪辑一定是专业技能过硬,有灵性化的思维,有剪辑大片的梦想,行动力强。在剪辑前要和编导沟通脚本,理解摄像的拍摄意图,整理原始素材,梳理自己的剪辑思路。 在剪辑过程中,会用到一些常用的剪辑软件,包括视频编辑软件、修图软件修图软件和动画制...

淘宝没有客服怎么解决客服回复率(淘宝商家客服没有人回复怎么办)

淘宝没有客服怎么解决客服回复率(淘宝商家客服没有人回复怎么办)

淘宝卖方应提前设置机器人的自动回复。如果人工客服未能及时回复买家信息,机器人的回复可以设置好,因为机器人的回复可以被视为有效回复。...

教你网站设计的关键点是什么。

教你网站设计的关键点是什么。

其实并没有很多人脑海中想象的那么复杂。有大多数人在几天之内就能建立属于自己的个人网站。那么,在构建网站时,我们必须清楚几个问题: 1、确定网站目的 根据产品的销售渠道和销售目标,很明显网站是信息服务类型、销售类型、销售服务类型或综合类型。公司企业的网站与个人消费者的网站完全不同,并非所...

了解供应商都有哪些渠道可挖掘?

了解供应商都有哪些渠道可挖掘?

了解供应源是有效采购的基本前提。一般情况下,主要的信息来源有商品目录、行业期刊、各类广告、商业介绍、供应商与销售代理商、因特网、销售记录、业务联系以及采购部门自己的记录等。一、商品目录众所周知,供应商商品目录包含了公司所需的大部分物料信息,它是管理良好的采购办公室中的必备之...

现在,非常期待与您的又一次邂逅

我们努力让每一部企业宣传片和抖音短视频成为商业大片