【备忘录】Kotlin协程(二)

(8)

/**
 * 协程的取消与超时
 */

fun main() = runBlocking {

    val myJob = GlobalScope.launch {
        repeat(200) {
            println("hello $it")
            delay(500)
        }
    }

    delay(1100)
    println("Hello World")

    //协程取消
    myJob.cancel()
    //join()作用:等待启动的线程的任务完成
    myJob.join()

//    myJob.cancelAndJoin()// 取消一个作业并且等待它结束

    println("Welcome")
}

运行结果

hello 0
hello 1
hello 2
Hello World
Welcome

( 9 )

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

fun main() = runBlocking {

    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        while (i < 10) {
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I am sleeping ${i++}")
                nextPrintTime += 500L
            }
        }
    }

    delay(1300)
    println("Hello World")

    job.cancelAndJoin()
    println("Welcome")
}
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
Welcome

(10)

/**
 *有两种方式可以让计算代码变为可取消的
 * 1.周期性的调用一个挂起函数,该挂起函数会检查取消状态,比如使用【yield】函数
 * 2.显式的检查取消状态
 *
 * 如下示例使用第二种方式
 * isActive是协程的一个扩展属性,他是通过CoroutineScope对象添加的
 */

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()//将while的active变为false
    println("Welcome")
}
Job: I am sleeping 0
Job: I am sleeping 1
Job: I am sleeping 2
Hello world
Welcome

(11)

/**
 * 使用finally来关闭资源
 * join和cancelAndjoin都会等待所有清理动作完成才会继续往下执行
 */

fun main() = runBlocking {

    val myjob = launch {
        try {
            repeat(100) {
                println("job: I am sleeping $it")
                delay(500)
            }
        } finally {
            println("执行了finally块")
        }
    }

    delay(1300)
    println("Hello World")

    myjob.cancelAndJoin()
    println("Welcome")
}
job: I am sleeping 0
job: I am sleeping 1
job: I am sleeping 2
Hello World
执行了finally块
Welcome

(12)

/**
 * 当我们在协程的finally块中使用了挂起函数时,会导致CancellationException异常,
 * 原因在于运行该代码块的协程已经被取消了。
 * 通常情况下,这并不会产生什么大问题,因为大多数关闭操作(比方说取消一个job、关闭网络操作等)
 * 通常都是非阻塞的,并不需要使用挂起函数;
 * 然而,在极少数情况下,当我们在一个取消的协程中进行挂起操作时,我们可以将相应的代码
 * 放置到withContext(NonCancellable){}当中,
 * 在这种结构中,我们实际上使用了withContext函数与NonCancellable上下文
 */

fun main() = runBlocking {

    val myjob = launch {
        try {
            repeat(100) {
                println("job: I am sleeping $it")
                delay(500)
            }
        } finally {
            withContext(NonCancellable) {
                println("执行了finally块")
                delay(1000)
                println("在delay后执行的代码块")
            }
        }
    }

    delay(1300)
    println("Hello World")

    myjob.cancelAndJoin()
    println("Welcome")
}
job: I am sleeping 0
job: I am sleeping 1
job: I am sleeping 2
Hello World
执行了finally块
在delay后执行的代码块
Welcome

(13)

/**
 * 我们在使用协程时,如果取消了协程,那么很大一部分原因都在于协程的执行时间超过了某个设定值,
 * 我们可以通过手工引用与协程对应的job的
 * 方式来启动一个单独的协程用于取消这个协程,不过Kotlin提供了一个内建的函数
 * 来帮助我们又快又好地做到这一点
 */

fun main() = runBlocking {

    withTimeout(1900) {
        repeat(1000) {
            println("Hello $it")
            delay(400)
        }
    }
}
Hello 0
Hello 1
Hello 2
Hello 3
Hello 4
Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException:
 Timed out waiting for 1900 ms
	at kotlinx.coroutines.TimeoutKt.TimeoutCancellationException(Timeout.kt:158)
	at kotlinx.coroutines.TimeoutCoroutine.run(Timeout.kt:128)
	at kotlinx.coroutines.EventLoopImplBase$DelayedRunnableTask.run(EventLoop.common.kt:497)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
	at kotlinx.coroutines.DefaultExecutor.run(DefaultExecutor.kt:68)
	at java.lang.Thread.run(Thread.java:748)

(14)

/**
 * 由withTimeout函数调用所抛出的TimeoutCancellationException异常是CancellationException的子类,
 * 当该异常抛出时,我们并未在控制台上看到整个异常堆栈信息,这是因为在取消的过程中,
 * CancellationException被认为是一种协程完成的正常的原因而已。
 *
 * 不过,我们在该实例中,是在main函数中调用了withTimeout函数调用
 *
 * 既然CancellationException仅仅只是个异常而已,所有的资源也都会以通常的方式来关闭,
 * 那么我们就可以将相关代码放到一个try...catch块中;
 * 此外,Kotlin还提供了另外一个更加友好的函数调用:withTimeoutOrNull;从功能来看,
 * 它非常类似withTimeout,不过当超时发生时,它并不会跑跑抛出CancellationException异常,
 * 而是直接返回null
 *
 * 对于withTimeout函数调用来说,如果将其放置到try...catch中,那么调用的形式就是下面这样:
 *
 * try {
 *     ...
 * } catch (ex: TimeoutCancellationException){
 *     ...
 * }
 */

fun main() = runBlocking {
    val result = withTimeoutOrNull(1900) {
        repeat(2) {
            println("hello,$it")
            delay(300)
        }

        "hello world"
    }

    println("result is $result")
}
hello,0
hello,1
result is hello world
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值