Kotlin协程“在发生之前”的保证?

时间:2019-10-23 08:38:11

标签: kotlin concurrency kotlin-coroutines happens-before

Kotlin协程是否提供任何“事前保证”?

例如,在这种情况下,写入mutableVar与随后(可能)在其他线程上进行后续读取之间是否存在“先于后继”保证:

suspend fun doSomething() {
    var mutableVar = 0
    withContext(Dispatchers.IO) {
        mutableVar = 1
    }
    System.out.println("value: $mutableVar")
}

编辑:

也许其他示例可以更好地阐明这个问题,因为它更具Kotlin风格(可变性除外)。这段代码是线程安全的吗?

suspend fun doSomething() {
    var data = withContext(Dispatchers.IO) {
        Data(1)
    }
    System.out.println("value: ${data.data}")
}

private data class Data(var data: Int)

2 个答案:

答案 0 :(得分:6)

您编写的代码具有三种访问共享状态的权限:

var mutableVar = 0                        // access 1, init
withContext(Dispatchers.IO) {
    mutableVar = 1                        // access 2, write
}
System.out.println("value: $mutableVar")  // access 3, read

这三个访问严格按顺序进行排序,它们之间没有并发,并且您可以放心,Kotlin的基础结构在移交给{{1}时会照顾到在发生之前先发生边缘的情况。 }线程池并返回到您的调用协程。

下面是一个等效的示例,也许看起来更令人信服:

IO

由于launch(Dispatchers.Default) { var mutableVar = 0 // 1 delay(1) mutableVar = 1 // 2 delay(1) println("value: $mutableVar") // 3 } 是一个可挂起的函数,并且由于我们使用的是由线程池支持的delay调度程序,因此行1,行2和行3可能分别在不同的线程上执行。因此,关于 happen-before 保证的问题同样适用于此示例。另一方面,在这种情况下(我希望)是完全显而易见的,该代码的行为与顺序执行的原理一致。

答案 1 :(得分:3)

科特琳的协约确实在保证发生之前提供了援助。

规则是:在一个协程中,暂停功能调用的代码之前 先于发生在之后。 / p>

您应该将协程视为常规线程:

  

即使Kotlin中的协程可以在多个线程上执行,但从可变状态的角度来看,它就像一个线程。同一协程中不能同时执行两个动作。

来源:https://proandroiddev.com/what-is-concurrent-access-to-mutable-state-f386e5cb8292

回到代码示例。在lambda函数体中捕获var不是最好的主意,尤其是当lambda是协程时。 Lambda之前的代码不会在内部代码之前发生。

请参见https://youtrack.jetbrains.com/issue/KT-15514