Pab*_*dez 7 java concurrency thread-safety shared-memory
可能重复:
Java类中的线程安全性
我在实践中阅读Java并发性,并且我找到了一个令我困惑的例子.
作者声明这个类不是线程安全的
public class MutableInteger {
private int number;
public int getInt() {
return number;
}
public void setInt(int val) {
number = val;
}
}
Run Code Online (Sandbox Code Playgroud)
并且他们还声明只同步一个方法(例如setter)不会; 你必须同步两者.
我的问题是:为什么?不会同步setter吗?
Java在内存模型之前/之后发生.在写路径和读路径上都需要有一些常见的并发构造(例如,同步块/方法,锁,易失性,原子)来触发此行为.
如果同步这两个方法,则会在整个对象上创建一个锁,该锁将由读写线程共享.JVM将确保在离开(synchronized)setInt方法之前在写入线程上发生的任何更改在进入(synchronized)getInt方法后对任何读取线程都是可见的.JVM将插入必要的内存屏障以确保发生这种情况.
如果仅同步write方法,则对任何读取线程可能看不到对象的更改.这是因为JVM可以使用读取路径来确保读取线程的可见内存(缓存等)与写入线程一致.使getInt方法同步将提供.
注意:特别是在这种情况下,使字段'number'为volatile将提供正确的行为,因为volatile读/写也在JVM中提供相同的内存可见性行为,并且setInt方法内部的操作只是一个赋值.
在样本之前的书中对此进行了解释(第35页):
"只同步setter是不够的:调用get的线程仍然可以看到陈旧的值."
陈旧数据:当读者线程检查就绪时,它可能会看到过时的值.除非每次访问变量时都使用同步,否则可能会看到该变量的陈旧值.更糟糕的是,陈旧不是全有或全无:线程可以看到一个变量的最新值,但是第一个写入的另一个变量的陈旧值.