Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java并发性-为什么';同步setter(而不是getter)不能使类线程安全吗?_Java_Concurrency_Shared Memory_Thread Safety - Fatal编程技术网

Java并发性-为什么';同步setter(而不是getter)不能使类线程安全吗?

Java并发性-为什么';同步setter(而不是getter)不能使类线程安全吗?,java,concurrency,shared-memory,thread-safety,Java,Concurrency,Shared Memory,Thread Safety,可能重复: 我在实践中阅读Java并发性,我遇到了一个让我困惑的例子 作者声明该类不是线程安全的 public class MutableInteger { private int number; public int getInt() { return number; } public void setInt(int val) { number = val; } } 他们还声明只同步一个方法(例如setter)是

可能重复:

我在实践中阅读Java并发性,我遇到了一个让我困惑的例子

作者声明该类不是线程安全的

public class MutableInteger {

    private int number;

    public int getInt() {
        return number;
    }

    public void setInt(int val) {
        number = val;
    }
}
他们还声明只同步一个方法(例如setter)是不行的;你必须将两者同步


我的问题是:为什么?同步setter不就是这样吗?

Java有一个before/before-after内存模型。在写入路径和读取路径上都需要一些常见的并发构造(例如,同步块/方法、锁、易失性、原子)来触发这种行为

如果同步这两个方法,则将在整个对象上创建一个锁,该锁将由读线程和写线程共享。JVM将确保在离开(同步的)setInt方法之前在写入线程上发生的任何更改,在进入(同步的)getInt方法之后,对任何读取线程都是可见的。JVM将插入必要的内存屏障,以确保实现这一点

如果只同步写入方法,则任何读取线程都可能看不到对对象的更改。这是因为在读取路径上没有JVM可以用来确保读取线程的可见内存(缓存等)与写入线程一致的点。使getInt方法同步将提供这一点


注意:特别是在这种情况下,将字段“number”设置为volatile将给出正确的行为,因为volatile读/写也在JVM中提供相同的内存可见性行为,setInt方法内部的操作只是一个赋值。

因为
number
不是volatile,而且
getInt()
未同步,
getInt()
可能会返回过时的值。有关更多信息,请阅读java内存模型。

示例之前的书(第35页)对此进行了解释:

“仅同步setter是不够的:调用get的线程仍然能够看到过时的值。”


陈旧数据:当读卡器线程检查就绪时,它可能会看到一个过期的值。除非每次访问变量时都使用同步,否则可能会看到该变量的过时值。更糟糕的是,过时并不是全部或全无:线程可以看到一个变量的最新值,但可以看到另一个先写入的变量的过时值。

如果只同步setter方法,则只能保证属性不会被错误修改,但是,当您尝试读取变量时,无法确定它是否过时

对不起,答案至少是不完整的,而且这个提示对我的眼睛是无用的。他要求对一个具体问题进行解释(-1)这是一个典型的注释行。使字段“number”易变并不会使赋值操作原子化。该方法必须同步如果字段不稳定且该方法未同步,则说明所涉及的实际故障场景。实际上,它有微妙的不同。我正在读这本书,说“它将能够看到过时的值”是不够的,我需要基础。所以,你不相信,如果getter没有同步,并且您想要证明它,那么就有可能看到过时的值,或者您的意思是什么?我想理解为什么。原因是线程保留变量的本地缓存值,读取可能不会刷新缓存。如果缓存不存在,那么是否存在同步方法就无关紧要(两个操作都是原子的)