在对Dispatchers.Main.immediate进行分析时,isDispatchNeeded正常分支很简单,但else分支足足套了3层,我说这里只是原地执行好没有说服力啊。所以一起来看看它这里在搞什么飞机。
好吧,注释已经告诉我们了,就是为了防StackOverflow。那么它是怎样做到的呢?
首先我们注意到这里有个EventLoop,它不是安卓中的looper,但其实与之类似。
可以看到,类似于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分支
先走了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