推广

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

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

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://www.0291.com.cn/post/57626.html

相关文章

我来教你企业营销推广费用如何计算。

我来教你企业营销推广费用如何计算。

要进行营销推广,那是需要一定的。以往的传统营销推广方式,费用比较容易计算,可如今进入了全网营销,费用的计算方式不同了。 对于企业来说,必须要精打细算,才能将费用利用到最好,下面钟振森主要给大家讲解一下网络营销推广的费用,希望对大家有所帮助。 (1)根据推广方式来收费。企业营销推广费用,如果是网络...

极速推多久才开始推广,极速推广99元有用吗?(淘宝客审核过多久能开始推广)

极速推多久才开始推广,极速推广99元有用吗?(淘宝客审核过多久能开始推广)

在淘宝极速推广中每天的金额是可以由商家来控制的,一般99元的推广费用用不了很长的时间,有些商家使用的推广费用会更高一些。...

年轻人应该做什么才能完成原始的财富积累?

年轻人应该做什么才能完成原始的财富积累?

年轻人应该做什么才能完成原始的财富积累?...

“玩”转B站企业号,品牌如何做好B站运营?

企业号是在B站与多圈层用户沟通、建立信任的重要阵地。2020年,B站企业号数量就已增长超2倍,更产出了一批令人惊喜的爆款,与B站Z世代用户打成一片,拉近了品牌与年轻用户人群的距离。疫情期间钉钉的《钉钉本钉》创下了B站蓝V破圈的记录,后来腾讯的“鹅厂大战老干妈”事件也在B站出...

2022中国资产管理与财富管理行业年度峰会暨第二届“金誉奖”颁奖典礼今日启动 资管业“奥斯卡”即将揭晓

2022中国资产管理与财富管理行业年度峰会暨第二届“金誉奖”颁奖典礼今日启动 资管业“奥斯卡”即将揭晓

金融投资报记者 吉雪娇6月17日,由普益标准与金融投资报社举办的“大资管?新视野:洞见资管变革 聚焦财富格局——2022中国资产管理与财富管理行业年度峰会暨第二届‘金誉奖’颁奖典礼”将拉开帷幕。随着居民财富管理意识的逐步提高,资产配置需求日益多元化,财富管理行业迎来高速发展...

百度推广和百度爱采购有什么区别?

百度推广和百度爱采购有什么区别?

目前我知道的爱采购模式有3种①会员模式(和阿里巴巴店铺一样,仅仅是开个店,费用较低,几千搞定)②爱采购竞价(百度的阿拉丁,扣费模式和大搜信息流一个道理)③爱采购竞价-丰采网合作模式(也是属于竞价模式,但是强烈不推荐,谁用谁倒霉,我开通过一次,简直无法用语言描述这个有多烂)效...

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

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