Kotlin协程笔记

2023-04-22  本文已影响0人  丹丹无敌

协程与线程关系

suspend修饰的挂起于协程的意义

fun main(array: Array<String>) {
    GlobalScope.launch {
        println("before suspend")//①
        testSuspend()//挂起函数②
        println("after suspend")//③
    }
}

执行到②时,协程被挂起,将不会执行③,直到协程被恢复后才会执行③。
suspend () -> T

无参,返回值为泛型。
Kotlin 里定义了一些扩展函数,可用来开启协程。

如何开启一个原始的协程

launch/async/runBlocking 如何开启协程

纵观这几种主流的开启协程方式,它们最终都会调用到:

#CoroutineStart.kt
    public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit =
        when (this) {
            DEFAULT -> block.startCoroutineCancellable(receiver, completion)
            ATOMIC -> block.startCoroutine(receiver, completion)
            UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion)
            LAZY -> Unit // will start lazily
        }

无论走哪个分支,都是调用block的函数,而block 就是我们之前说的被suspend 修饰的函数。

以DEFAULT 为例startCoroutineCancellable接下来会调用到IntrinsicsJvm.kt里的:

#IntrinsicsJvm.kt
public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted(
    receiver: R,
    completion: Continuation<T>
)

该函数带了俩参数,其中的receiver 为接收者,而completion 为协程结束后调用的回调。

为了简单,我们可以省略掉receiver。

刚好IntrinsicsJvm.kt 里还有另一个函数:

#IntrinsicsJvm.kt
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
    completion: Continuation<T>
): Continuation<Unit> 

createCoroutineUnintercepted 为 (suspend () -> T) 类型的扩展函数,因此只要我们的变量为 (suspend () -> T)类型就可以调用createCoroutineUnintercepted(xx)函数。

查找该函数的使用之处,发现Continuation.kt 文件里不少扩展函数都调用了它。

如:

#Continuation.kt
//创建协程的函数
public fun <T> (suspend () -> T).createCoroutine(
    completion: Continuation<T>
): Continuation<Unit> =
    SafeContinuation(createCoroutineUnintercepted(completion).intercepted(), COROUTINE_SUSPENDED)

其中Continuation 为接口:

#Continuation.kt
interface Continuation<in T> {
    //协程上下文
    public val context: CoroutineContext
    //恢复协程
    public fun resumeWith(result: Result<T>)
}

Continuation 接口很重要,协程里大部分的类都实现了该接口,通常直译过来为:"续体"。

创建完成后,还需要开启协程函数:

#Continuation.kt
//启动协程的函数
public inline fun <T> Continuation<T>.resume(value: T): Unit =
    resumeWith(Result.success(value))

Kotlin线程池与Java 线程池比对

全局捕获异常

与线程类似,协程也可以全局捕获异常。

    //创建处理异常对象
    val exceptionHandler = CoroutineExceptionHandler { _, exception ->
        println("handle exception:$exception")
    }
    fun testException3() {
        runBlocking {
            //声明协程作用域
            var scope = CoroutineScope(Job() + exceptionHandler)
            var job1 = scope.launch(Dispatchers.IO) {
                println("job1 start")
                //异常
                1 / 0
                println("job1 end")
            }
        }
    }
上一篇下一篇

猜你喜欢

热点阅读