Kotlin 协程中的可见性

Visibility in Kotlin coroutines

我决定深入研究 Kotlin 协程。我有一些关于可见性的问题。我知道在没有 ContinuationInterceptor 的情况下,相同协程的不同部分可能由不同的线程执行。

如何保证在挂起后,新线程对协程内部状态具有正确的可见性?

例如:

    suspend fun doPost(customRatings : Map<String, Int>) : Int {...}

    fun postRatings_1() {
        GlobalScope.launch {
            val mutableMap : MutableMap<String, Int> = mutableMapOf()

            mutableMap["Apple"] = 1
            mutableMap["Banana"] = 2

            // ...

            val postId = doPost(mutableMap)

            // How am I guaranteed to see the two entries here ?
            println("posted ${mutableMap} with id ${postId}") 
        }
    }

启动新协程时类似

    fun postRatings_2() {

        val mutableMap : MutableMap<String, Int> = mutableMapOf()

        mutableMap["Apple"] = 1
        mutableMap["Banana"] = 2


        GlobalScope.launch {
            // How am I guaranteed to see the two entries here ?
            val postId = doPost(mutableMap)
            //...
        }

在这两种情况下,两个(现有)线程之间共享一些可变状态。

我正在寻找 "Happens-before" 规则来保证可变状态将被两个线程正确可见。

I am looking for the "Happens-before" rule that guarantees that the mutable state will be properly visible by the two threads.

保证很容易获得:例如,如果您的调度程序基于 Java 线程池,则线程池本身已经提供了此保证。 executor.submit() 之前的代码调用 happens-before 提交的代码,而该代码又 happens-before 观察的代码相关未来的完成。

即使您使用称为 Dispatchers.Unconfined 的空分配器,它只是在您碰巧调用的任何线程上恢复协程 continuation.resume(result),您仍然会得到 happens-before 因为调用您的回调的底层框架对此有保证。

您必须在编写一个自定义的损坏 Dispatcher 实现时走得很远才能弄乱排序。