(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