Java 为什么会这样?(在主线程中生成值并在Android中的其他后台线程中使用)
据我所知,线程在本地缓存中复制变量。 我所做的是,在主线程中获取值,然后在其他后台(渲染器)线程中使用它们。像这样-Java 为什么会这样?(在主线程中生成值并在Android中的其他后台线程中使用),java,android,multithreading,kotlin,Java,Android,Multithreading,Kotlin,据我所知,线程在本地缓存中复制变量。 我所做的是,在主线程中获取值,然后在其他后台(渲染器)线程中使用它们。像这样- class MySurfaceView ... { private var someValue = 0 // Called from the main thread fun updateValue() { someValue++ } fun render() { Thread {
class MySurfaceView ... {
private var someValue = 0
// Called from the main thread
fun updateValue() {
someValue++
}
fun render() {
Thread {
// Here someValue variable is consumed
// and it's always up to date.
....
}.start()
}
}
因此,在传递给render()内启动的线程的runnable中,“someValue”始终是最新的,我甚至没有将其标记为volatile。如果线程将变量复制到本地缓存,那么为什么会发生这种情况?是否因为外部类的隐式引用被保留,而值来自于外部类(如果这是真的,那么在这种情况下,如果我有一个生成器和多个使用者线程,那么不将仅由生成器线程更新的字段标记为volatile是否总是安全的?因为volatile上的读/写操作是昂贵的)?
当我启动一个协同程序并尝试访问其中的“someValue”时,同样的事情也会发生
线程在本地缓存中复制变量
事实并非如此,这解释了您的发现。基本上,您混淆了实现可能行使的自由与规范提供的保证。Java内存模型(Kotlin也遵循该模型)简单地说,让实现可以自由地对未通过同步操作共享的状态执行任何操作。它可以将其存储在堆栈或寄存器中,也可以与堆上的原始状态一起工作
一个特别相关的细节是println()
是一个synchronized
方法,因此如果在实际代码中,您在两个线程中都有println
以查看发生了什么,那么您引入了同步,从而使结果正确
另一方面,以这种自由为例,很容易看到一个程序
Thread 1:
var runningFlag = true
while (runningFlag) {}
Thread 2:
sleep(1000)
runningFlag = false
线程1很可能永远执行下去,甚至被编译成类似于
currentThread().join()
——不做实际工作,但永远不会完成。“据我所知,线程在本地缓存中复制变量”--不。我仍然感到困惑。我知道变量并不总是复制到本地缓存。但是,在我问题中的示例这样的情况下不使用volatile或引入同步是安全的还是不安全的?它不安全。变量必须是volatile的,以确保另一个线程观察到它的更新。这就是我的代码片段的目的。