kotlin10.协程同步

244 阅读2分钟

多个挂起函数

同一协程下多个挂起函数,顺序执行.如下所示,test1()和test2()顺序执行,得到结果,并最终打印.

fun main() = runBlocking {
    var time = measureTimeMillis {
        val one = test1()
        val two = test2()
        val result = one + two
        println("result is $result")
    }
    println("end $time")
}

suspend fun test1():Int{
    delay(500)
    return 10
}

suspend fun test2():Int{
    delay(500)
    return 20
}
//输出
result is 30
end time cost 1016

异步执行多个挂起函数 async/await

  • 通过async可以并发启动两个协程
  • await等待协程结果
fun main() = runBlocking {
    var time = measureTimeMillis {
        val one = async {test1()}
        val two = async {test2()}
        val result = one.await() + two.await()
        println("result is $result")
    }
    println("end time cost $time")
}

suspend fun test1():Int{
    delay(500)
    return 10
}

suspend fun test2():Int{
    delay(500)
    return 20
}
//输出
result is 30
end time cost 521

async与launch

  • async和launch都返回一个job ,区别在于是否携带结果.
  • async返回了一个Deferred延期任务,能够通过await获得结果.Deferred也继承自job
  • launch返回一个job,不带结果
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine<T>(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

获取作业job

async {
    println("${Thread.currentThread().name} test a")
    println("${coroutineContext[Job]}")
    coroutineContext[Job]?.cancelAndJoin()
}

async 惰性任务 CoroutineStart.LAZY

  • 有时候定义好异步任务,不需要马上启动,这时候需要用惰性启动来定义任务.在满足条件的时候启动.
  • 如果不调用start,在await的时候,也会启动任务.但是会顺序执行.
fun main() = runBlocking {
    var time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) {test1()}
        val two = async(start = CoroutineStart.LAZY)  {test2()}
        one.start()
        two.start()
        val result = one.await() + two.await()
        println("result is $result")
    }
    println("end time cost $time")
}

同一作用域下多个异步任务

当有一个异步任务失败时,会造成同一作用域下其它任务失败.

fun main() = runBlocking {
    var time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) {test1()}
        val two = async(start = CoroutineStart.LAZY)  {test2()}

        one.start()
        two.start()
        val result = one.await() + two.await()
        println("result is $result")
    }
    println("end time cost $time")
}

suspend fun test1():Int{
    try {
        delay(Long.MAX_VALUE)
    }finally {
        println("test1 cancelled")
    }
    return 10
}

suspend fun test2():Int{
    delay(500)
    throw IllegalStateException("test2 exception")
    return 20
}

协程上下文与调度器

协程总是运行在协程上下文中,它是一些列元素的集合

  • 协程调度器 CoroutineDispatcher, 它确定协程运行在哪类线程上. MainCoroutineDispatcher/CoroutineDispatcher
  • 当没有指定上下文时,它默认从父协程中继承.
fun main() = runBlocking {

    launch(context = Dispatchers.Default){
        println("test default ${Thread.currentThread().name}")
    }

    launch {
        println("test Main ${Thread.currentThread().name}")
    }

    launch(context = Dispatchers.IO){
        println("test IO ${Thread.currentThread().name}")
    }

    //
    launch(context = Dispatchers.Unconfined){
        println("test Unconfined ${Thread.currentThread().name}")
    }

    coroutineScope {
        println("test coroutineScope ${Thread.currentThread().name}")
        20
    }

    println("end of main")
}
//输出
test default DefaultDispatcher-worker-1
test IO DefaultDispatcher-worker-1
test Unconfined main
test coroutineScope main
end of main
test Main main

协程调试

调试参数

image.png

-Dkotlinx.coroutines.debug

var a = async {
    println("${Thread.currentThread().name} test a")
}
a.start()

协程命名

可以支持组合多个context的属性, + 是在CoroutineContext中重载的运算符

fun main() = runBlocking {
    val v1 = async(Dispatchers.Default + CoroutineName("test")) {
        delay(400)
        println("coroutine ${Thread.currentThread().name}")
    }
}

父协程与子协程协同

父协程取消

当父协程取消时,会自动取消所有的子协程.子协程与父协程具有相同的scope.

fun main() = runBlocking {
    val req = launch {
        GlobalScope.launch {
            delay(100)
            println("start in global scope")
            delay(1000)
            println("end in global scope")
        }

        launch {
            delay(100)
            println("start in coroutine scope")
            delay(1000)
            println("will be canceled if parent canceled")
        }
    }

    delay(500)
    req.cancel()
    delay(1000)
    println("end of all")
}
//输出
start in coroutine scope
start in global scope
end in global scope
end of all

父协程等待

父协程总是等待所有子协程结束,才会结束自身.

fun main() = runBlocking {
    //如果把子协程放到这个作用域下,则all done 不会先执行
//    coroutineScope{
//
//    }

    val req = launch {
        repeat(3){
            delay((it + 1) * 300L)
            println("coroutine $it is done")
        }
        println("done !!!!!")
    }
    println("all done !!!!!")
}

协程与activity生命周期同步

在app中添加依赖

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1-native-mt"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1-native-mt"

构建全局的scope

private val mainScope = MainScope()

同步生命周期

override fun onDestroy() {
    super.onDestroy()
    mainScope.cancel()
}