kotlin之协程(二)
1.协程地取消与超时
isActive,隐含了CoroutineScope,本身是挂起函数。 当取消时,使用它的位置,遇到挂起函数,自动计算协程状态
package day8Coroutines
import kotlinx.coroutines.*
/**
* 协程取消时,有一种情况,是无法取消的, 该函数正在计算中
* 取消的原理,只有当遇到挂起函数时,会自动计算当前协程状态
*
*/
fun main(args: Array<String>) {
runBlocking {
var myJob = GlobalScope.launch { //suspend CoroutineScope.() -> Unit
repeat(200) { //重复0 - 200,可以用来做定时
println("$it")
delay(500)
}
isActive //隐含了CoroutineScope
}
delay(1000)
println("你好")
myJob.cancel()
myJob.join()
println("欢迎")
}
}
2.取消正在计算的协程
密集型计算,会导致线程卡死,相应线程中的协程根本不会执行。导致协程不能取消。
package day8Coroutines
import kotlinx.coroutines.*
/**
* 正在
*/
fun main(args: Array<String>) {
runBlocking {
var job = launch(Dispatchers.Default) {
var count = 0
try {
while (isActive) {
count++
}
} finally {
println("世界安静了")
}
}
delay(1000)
/**
* 下面这种方式会导致卡死,原因是delay先执行,然后程序一直在做空轮转,导致线程卡死。线程中的协程根本不会执行
*/
// var job = launch() {
// var count = 0
// while (isActive) {
// count++
// }
// }
delay(200)
println("开始")
job.cancelAndJoin()
println("结束")
}
}
3.取消协程案例
多个withConext是串行执行。本质原因是withConext是一个挂起函数。
withContext{}
不会创建新的协程,在指定协程上运行挂起代码块,并挂起该协程直至代码块运行完成。简单说,就是在已有(并非原有)协程上挂起。
package day8Coroutines
import kotlinx.coroutines.*
/**
* 使用withContext函数 来解决取消协程的问题
*/
fun main(args: Array<String>) {
runBlocking {
var job = launch(Dispatchers.Default) {
var count = 0
try {
while (isActive) {
count++
}
} finally {
// println("世界安静了") // 这里就已经结束了
// delay(1000) //这一段执行时,会直接抛出CancellationException异常,后面就不会执行了
// println("新的一天开始了") //这一段不会开始,原因是,该协程已经取消了,大多数情况都不会发生阻塞,比如网络情况,那么解决这种问题了
/**
* 开启一个新的协程,NonCancellable默认不会取消的协程
*/
withContext(NonCancellable) {
println("世界安静了")
delay(1000)
println("新的一天开始了")
}
}
}
delay(1000)
delay(200)
println("开始")
job.cancelAndJoin()
println("结束")
}
}
4.withTimeOut超时协程取消
package day8Coroutines
import kotlinx.coroutines.isActive
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
/**
* 超时时,可以手动取消协程,也可以使用kotlin中提供的内奸函数来帮助我们解决问题
* 注意:正在计算中的协程依旧无法取消
*
*/
fun main(args: Array<String>) {
runBlocking {
withTimeout(1900) {
// repeat(100) {
// println("$it")
// delay(100)
// }
var count = 0
try {
while (isActive) {
count++
}
} finally {
println("世界安静了")
}
}
}
}
5.withTimeOutOrNull协程超时
package day8Coroutines
import kotlinx.coroutines.*
/**
* 如果使用如果使用withTimeout,则需要使用try catch 捕捉CancellationException异常
* 更好的方式,是使用withTimeoutOrNukk,类似与如果使用withTimeout,但不会抛出CancellationException异常,而是直接返回null
* withTimeout和是使用withTimeoutOrNull是一个挂起函数
*
*
*/
fun main(args: Array<String>) {
runBlocking {
try {
withTimeout(1900) {
repeat(100) {
println("$it")
delay(100)
}
}
} catch (e: CancellationException) {
}
var result = withTimeoutOrNull(2000) {
repeat(100) {
println("$it")
delay(100)
}
}
println("$result")
}
}
6.协程并发
采用挂起函数来串行执行。
package day8Coroutines
import kotlinx.coroutines.*
import java.lang.Exception
import kotlin.system.measureTimeMillis
/**
* 协程并发
* 1.下面中方式,在开发中基本不会使用到,使用挂起函数来顺序执行,
* 缺陷:如果initValue()发生异常,那么initValue2()不会执行
* 2:这种方式的并不是真正的并发
*
*/
fun main(args: Array<String>) {
runBlocking {
// try {
// val time = measureTimeMillis {
// val value = initValue()
// val value2 = initValue2()
// println("结果:${value + value2}")
// }
// } catch (e: Exception) {
//
// }
initValue3()
initValue4()
}
}
private suspend fun initValue(): Int {
delay(2000)
return 20
}
private suspend fun initValue2(): Int {
delay(2000)
return 50
}
fun initValue3(): Job = GlobalScope.launch {
delay(100)
initValue()
}
fun initValue4(): Job = GlobalScope.launch {
delay(100)
initValue2()
}
7.async和await实现更加合理的并发
async:它会开启一个新的协程.会返回一个Deffered非阻塞的future
await:挂起函数,会阻塞协程。
package day8Coroutines
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlin.system.measureTimeMillis
/**
* 在kotlin中,async和await并不是关键字,只是扩展函数
* async:同launch一样,它会开启一个新的协程区别是,会返回一个Deffered非阻塞的future,可以稍后获取结果值
* await:挂起函数,会阻塞协程
*/
fun main(args: Array<String>) {
runBlocking {
val time = measureTimeMillis {
val v1 = async {
initValue()
}
val v2 = async {
initValue2()
}
//实现了并发,获取值
var result1 = v1.await()
var result2 = v2.await()
println("${result1 + result2}")
}
}
}
private suspend fun initValue(): Int {
delay(2000)
return 20
}
private suspend fun initValue2(): Int {
delay(2000)
return 50
}
var result1 = v1.await()
var result2 = v2.await()
println("${result1 + result2}")
}
}
}
private suspend fun initValue(): Int {
delay(2000)
return 20
}
private suspend fun initValue2(): Int {
delay(2000)
return 50
}