Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.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 getter和setter应该同步吗?_Java_Synchronized - Fatal编程技术网

Java getter和setter应该同步吗?

Java getter和setter应该同步吗?,java,synchronized,Java,Synchronized,在上面的示例中,让getter同步有什么意义吗?我认为最好在这里引用: 假设只有在写入共享变量时才需要使用同步,这是一个常见的错误;这根本不是事实 对于可由多个用户访问的每个可变状态变量 线程,对该变量的所有访问必须使用相同的 锁上了。在这种情况下,我们说变量由 锁 在没有同步的情况下,编译器、处理器和运行时可以对操作的执行顺序做一些完全奇怪的事情。试图推断在同步不足的多线程程序中内存操作“必须”发生的顺序几乎肯定是错误的 通常,您不必对原语如此小心,因此如果这是int或boolean,则可能是

在上面的示例中,让getter同步有什么意义吗?

我认为最好在这里引用:

假设只有在写入共享变量时才需要使用同步,这是一个常见的错误;这根本不是事实

对于可由多个用户访问的每个可变状态变量 线程,对该变量的所有访问必须使用相同的 锁上了。在这种情况下,我们说变量由 锁


在没有同步的情况下,编译器、处理器和运行时可以对操作的执行顺序做一些完全奇怪的事情。试图推断在同步不足的多线程程序中内存操作“必须”发生的顺序几乎肯定是错误的

通常,您不必对原语如此小心,因此如果这是
int
boolean
,则可能是:

当线程在没有同步的情况下读取变量时,它可能会看到 过时的值,但至少它可以看到实际放置的值 这里有一些线程,而不是一些随机值

但是,对于64位操作,例如在
long
double
上,如果未声明为
volatile
,则情况并非如此:

Java内存模型需要fetch和 存储操作是原子的,但对于非易失性的long和double 变量,JVM可以将64位读或写处理为两个 单独的32位操作。如果读取和写入以不同的方式进行 线程,因此可以读取非易失性long并获取 返回一个值的高32位和另一个值的低32位

因此,即使您不关心过时的值,使用它也是不安全的 多线程程序中共享可变长变量和双变量 除非它们被宣布为易变或由锁保护


让我通过示例向您展示JIT编译代码的合法方式。你写道:

private double value;

public synchronized void setValue(double value) {
    this.value = value;
}
public double getValue() {
    return this.value;
}
JIT编译:

while (myBean.getValue() > 1.0) {
  // perform some action
  Thread.sleep(1);
}
在稍微不同的场景中,甚至Java编译器也可以生成类似的字节码(它只需要消除动态分派到不同的
getValue
)的可能性。这是一个吊装的教科书示例


为什么这是合法的?编译器有权假设执行上述代码时,
myBean.getValue()
的结果永远不会改变。如果没有同步,则允许忽略其他线程的任何操作。

这里的原因是防止任何其他线程在线程读取时更新值,从而避免对过时的值执行任何操作

这里get方法将获取“this”上的内在锁,因此可能尝试使用setter方法设置/更新的任何其他线程都必须等待获取“this”上的锁,才能进入执行get的线程已经获取的setter方法

这就是为什么在可变状态下执行任何操作时,建议遵循使用相同锁的做法

由于没有复合语句,因此在这里使字段不稳定将起作用


需要注意的是,同步方法使用内在锁,即“this”。因此,同步get和set意味着任何进入该方法的线程都必须获得该方法的锁


在执行非原子64位操作时,应特别考虑。从Java并发实践中摘录的内容有助于理解这种情况-

“Java内存模型要求获取和存储操作是原子的,但对于非易失性长变量和双变量,JVM允许将64位读或写作为两个独立的32位 位操作。如果读取和写入发生在不同的线程中,则可以读取非易失性long并返回一个值的高32位和另一个值的低32位。因此,即使您不关心过时的值,它也会 在多线程程序中使用共享可变长变量和双变量是不安全的,除非声明它们
易变的或由锁保护的。”

也许对于某些人来说,这段代码看起来很糟糕,但它工作得很好

if (myBean.getValue() > 1.0) 
  while (true) {
    // perform some action
    Thread.sleep(1);
  }

更详细地说,如果希望在多线程应用程序中获得最新版本的值,则应该同步getter和setter。如果,出于某些非常奇怪的原因,您不关心获取最新版本,并且同步占用了太多时间(这种情况不太可能!),我认为您可以不同步getter。除非在这种情况下,-double是64位的,所以它应该始终被同步。@user949300不同步getter是不正确的。您可能永远都不会看到var的更改。@user949300不仅无法获得最新版本,而且您甚至不知道将获得哪个版本,而且该版本可能因线程而异。这几乎是不可接受的场景……”“在没有同步的情况下,编译器、处理器和运行时可以对操作的执行顺序做一些完全奇怪的事情”——参见示例17.4.5-1(在一致性之前发生)在@gasan中,JVM是32位还是64位无关紧要,因为我们在规范级别讨论这个问题。JLS将
long
double
操作指定为非原子操作。但是,所有这些都与新的内存模型定义无关,在新的内存模型定义中,很明显,如果没有适当的
,就没有交易发生在
排序之前。如果您使用的是Java 1.5或更大版本,并且只使用set和get(
setValue
则不必同步),则使双字段不稳定将是令人满意的。参见java.util.concurrent.atomic.atomic*类和已经引用的java并发性实践。@s106mo这在al上有效
  private Double value;
  public  void setValue(Double value){
    updateValue(value, true);
  }
  public Double getValue(){
      return updateValue(value, false);
  }
  private double updateValue(Double value,boolean set){
    synchronized(MyClass.class){
      if(set)
        this.value = value;
      return value;
    }
  }