在 Java/Kotlin 或任何 JVM 语言中,每个线程都有一个“本地内存”AKA。 “缓存”。当线程想要将变量写入内存时,它首先更新自己缓存中的值,然后将修改同步到主内存中,该内存在线程之间共享。
以下演示说明了发生线程未实现更改的用例:
class VolatileExample3 {
var flag = false
var a = 0
fun write() {
a = 1
Thread.sleep(10)
flag = true
}
companion object {
@JvmStatic
fun test() {
val example = VolatileExample3()
val th = Thread {
example.write()
}
th.start()
while (!example.flag) {}
println("a = ${example.a}")
}
}
}
线程th调用函数
write()
,首先更新a
的值,然后休眠10ms作为模拟IO操作,最后将flag设置为true表示“写入”已经完成。
在主线程中,当
flag
为true时,它总是查询flag的值并跳过while循环,这应该是write()
结束的时间。
我们希望输出为“a = 1”,这就是写入后的正确答案。
但是,因为“本地内存/缓存”的存在,主线程会像卡住一样在
while
中循环。
在
write()
的内容运行之前,主线程首先读取 flag
并得到 false,除非我们明确告诉它,否则它不会获取主内存中的值。
问题的答案很明显:将
@Volatile
添加到 flag
,其中 READ
操作将使其本地内存在真正的 LOAD VALUE
之前无效。
但是我找到了这个问题的另一种解决方案:
while (!example.flag) {
print("")
}
无需
@Volatile
即可工作!我想知道flush cache
内部的print()
操作是否会使主线程的本地内存/缓存无效。如果有的话,机制是什么?
我还发现将
th.join()
放在 while 循环之前也有效。这些方法本质上是相同的吗?这意味着一个线程的终止会被所有其他线程注意到,从而导致本地内存失效?
如果我将 th.join() 添加到 while 循环中,也会导致主线程缓存失效。为什么会出现这种情况?