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)
答案 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之前的代码不会在内部代码之前发生。