栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Kotlin - Job 任务/取消

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Kotlin - Job 任务/取消

任务取消的状态

仅仅终止线程是一个糟糕的方案,协程的取消能够更好的检查状态关闭释放资源。

  • 运行出错或者调用cancel()后该job会在遇到第一个挂起点开始取消并抛出CancellationException异常(先处于Cancelling状态:isActive=false,isCancelled=true)(没有挂起点便不会响应cancel()操作),之后会调用join()让协程挂起把该job的取消执行完后(再处于Cancelled状态:isCompleted=true,isCancelled=true)才能继续执行其它,否则会存在其它协程并发执行。推荐使用cancelAndJoin()简化调用。
  • 一旦该job被取消,该job下的子job也会一并取消,但父job和兄弟job不受影响,该job不能再用作任何新job的父job(不能开启新协程)。

Job的状态/函数判断isActive( )isCompleted( )isCancelled( )
New 新创建(optional initial state)falsefalsefalse
Active 活跃(default initial state)truefalsefalse
Completing 完成中(transient state)truefalsefalse
Cancelling 取消中(transient state)falsefalsetrue
Cancelled 已取消(final state)falsetruetrue
Compeleted 已完成(final state)falsetruefalse
任务取消的异常处理

协程通过抛出一个 CancellationException异常 来取消 Job。cancel() 可以传参使用不同的异常来指定原因,需要是 CancellationException 的子类才能取消协程。该异常不会导致父协程或其它子协程的取消,可以使用 try-catch-finally 去捕获处理释放资源,推荐使用标准函数 use() 会自动关闭资源。

suspend fun main() = runBlocking {
    //没有继承父协程的上下文,有自己的作用域,因此 runBlocking 不会等待 GlobalScope 执行完再结束。
    val job = GlobalScope.launch {
        try {
            //耗时操作
        }catch (e:Exception){
            //处理异常
        }finally{
            //释放资源
        }
    }
    delay(1000)  //让job运行一下再取消
//    job.cancel()    //抛异常 JobCancellationException
//    job.join()    //挂起函数,这样就会等 GlobalScope 取消完再继续执行
    job.cancelAndJoin() //简写
}
无法直接取消的任务(CPU密集型、没有挂起点)

由于调用cancel()操作后Job会处于Cancelling状态,此时只需判断Job是否处于活跃状态于便可以响应cancel()操作。

  • CPU密集型任务无法直接被cancel()取消,因为直接取消会丢失临时计算数据。可以通过对Job状态的判断来响应cancel()操作。
  • Job的取消发生在挂起点上,没有挂起点便不会响应cancel()操作,当我们使用协程却没有调用任何挂起函数的时候(做阻塞操作、神经网络学习)便会发生这种情况。

isActive

加在判断里

是一个CoroutineScope的扩展属性,判断Job是否处于活跃状态。

ensureActive()

写在函数里

是一个CoroutineScope的扩展函数,返回coroutineContext扩展函数,调用Job的函数,最终调用的是 !isActive,Job处于非活跃状态就报错CancelllationException。

yield()

不至于抢占太多线程让其它协程拿不到执行权

会检查所在协程的状态,如果已经取消则报错 CancellationException,此外会尝试让出线程执行权。
suspend fun main() = runBlocking {
    val job = launch(Dispatchers.Default) {    //该协程中无挂起点
        while (isActive) {   //判断出false便会取消
            ensureActive()              //检测出false便会取消
            yield()                     //不至于因为任务太抢占资源导致其它协程拿不到线程执行权
            println("CPU密集任务")
        }
    }
    delay(1000)    //让job运行一会儿后再取消
    println("等完")
    job.cancelAndJoin() //cancel()操作会将 isActive = false
    println("结束")
}
一定无法取消的任务

由于我们可以捕获CancellationException异常,在 Job 真正结束前可以做一些事情,由于 Job 响应 cancel() 后已经处于 Cancelling状态,此时启动一个新协程(会被忽略)或者调用挂起函数(会抛异常CancellationException)是无法被执行的。

  • 方式①:指定协程上下文为NonCancellable来得到一个常驻Job不响应 cancel()操作。
  • 方式②:使用invokeOnCompletion()函数,当 Job 处于Cancelled状态或Compeleted状态时会执行回调。形参it是一个异常,没有异常值为null,协程被取消值为 CancellationException。
withContext(NonCancellable){ 
    //不会响应取消
}
job.invodeOnCompletion{
    //回调代码
}

CancellableContinuation

suspendCancellableCoroutine

自定义协程取消时所作的操作。

//定义
suspend fun getResource():StudentBean = suspendCancellableCoroutine{ continuation ->
    request(object : ICallBack{
    override fun onSuccess(data:String){
        continuation.resume(data)
    }
    override fun onFailure(exception:Throwable){
        continuation.resumeWithException(exception)
    }
})    
    //定义协程取消时应该做的操作
    continuation.invokeOnCancellation{ //TODO... }
}

//使用
suspend main() = runBlocking{
    try{
        viewModelScope.launch{
            val bean = getResource()
        }
    }catch(e : Exception){
        e.printStackTrace()
    }
}
超时取消的任务 

超时取消Job,报错不处理会导致程序结束。

withTimeout()

public suspend fun withTimeout(timeMillis: Long, block: suspend CoroutineScope.() -> T): T

超时取消,抛出异常会结束程序。

withTimeoutOrNull()

public suspend fun withTimeoutOrNull(timeMillis: Long, block: suspend CoroutineScope.() -> T): T? 

超时取消并返回null,替代抛出异常。

withTimeout(1000) {
    println("")
}
withTimeoutOrNull(1000) {
    println("")
} ?: "值为空"
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020357.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号