executeUnconfined搞了什么飞机
在对Dispatchers.Main.immediate进行分析时,isDispatchNeeded正常分支很简单,但else分支足足套了3层,我说这里只是原地执行好没有说服力啊。所以一起来看看它这里在搞什么飞机。

在对Dispatchers.Main.immediate进行分析时,isDispatchNeeded正常分支很简单,但else分支足足套了3层,我说这里只是原地执行好没有说服力啊。所以一起来看看它这里在搞什么飞机。

resumeWith

executeUncofined

好吧,注释已经告诉我们了,就是为了防StackOverflow。那么它是怎样做到的呢?

首先我们注意到这里有个EventLoop,它不是安卓中的looper,但其实与之类似。

ThreadLocalEventLoop

可以看到,类似于Looper,它也被保存到ThreadLocal。

internal abstract class EventLoop : CoroutineDispatcher() {
    private var useCount = 0L
    private var unconfinedQueue: ArrayQueue<DispatchedTask<*>>? = null
    
    public fun dispatchUnconfined(task: DispatchedTask<*>) {
        val queue = unconfinedQueue ?:
            ArrayQueue<DispatchedTask<*>>().also { unconfinedQueue = it }
        queue.addLast(task)
    }

    public val isUnconfinedLoopActive: Boolean
        get() = useCount >= delta(unconfined = true)

    private fun delta(unconfined: Boolean) =
        if (unconfined) (1L shl 32) else 1L

    fun incrementUseCount(unconfined: Boolean = false) {
        useCount += delta(unconfined)
        if (!unconfined) shared = true 
    }

    fun decrementUseCount(unconfined: Boolean = false) {
        useCount -= delta(unconfined)
        if (useCount > 0) return
        assert { useCount == 0L } // "Extra decrementUseCount"
        if (shared) {
            // shut it down and remove from ThreadLocalEventLoop
            shutdown()
        }
    }
}

useCount初始值为0,即isUnconfinedLoopActive为false,所以第一次走else分支

runUnconfinedEventLoop

先走了incrementUseCount之后,isUnconfinedLoopActive就为true了。所以执行第一次的block过程中如果有executeUnconfined,它只是被添加到队列中,直到block执行完才依次得到执行,最后恢复useCount取值。

试想以下例子

  • executeUnconfined(…) { // A

  • executeUnconfined(…) { // B

  • executeUnconfined(…) { // C

  • }

  • }

}

正常执行到C处时,调用栈已经变成楼梯的样子了

A

….B

​ ….C

但现在用了类似消息循环处理的方式,执行A时先让B入队,A执行完成B才出队执行,B执行完时C才出队执行,最终调用栈中只有C。

先走了incrementUseCount之后,isUnconfinedLoopActive就为true了。所以执行第一次的block过程中如果有executeUnconfined,它只是被添加到队列中,直到block执行完才依次得到执行,最后恢复useCount取值。

试想以下例子

  • executeUnconfined(…) { // A

  • executeUnconfined(…) { // B

  • executeUnconfined(…) { // C

  • }

  • }

}

正常执行到C处时,调用栈已经变成楼梯的样子了

A

….B

​ ….C

但现在用了类似消息循环处理的方式,执行A时先让B入队,A执行完成B才出队执行,B执行完时C才出队执行,最终调用栈中只有C。

先走了incrementUseCount之后,isUnconfinedLoopActive就为true了。所以执行第一次的block过程中如果有executeUnconfined,它只是被添加到队列中,直到block执行完才依次得到执行,最后恢复useCount取值。

试想以下例子

  • executeUnconfined(…) { // A

  • executeUnconfined(…) { // B

  • executeUnconfined(…) { // C

  • }

  • }

}

正常执行到C处时,调用栈已经变成楼梯的样子了

A

….B

​ ….C

但现在用了类似消息循环处理的方式,执行A时先让B入队,A执行完成B才出队执行,B执行完时C才出队执行,最终调用栈中只有C。

画板


最后修改于 2023-04-17