吸气剂和二传手应该同步吗?

DD.*_*DD. 58 java synchronized

private double value;

public synchronized void setValue(double value) {
    this.value = value;
}
public double getValue() {
    return this.value;
}
Run Code Online (Sandbox Code Playgroud)

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

Kon*_*che 76

我认为最好这里引用Java Concurrency in Practice:

假设只有在写入共享变量时才需要使用同步,这是一个常见的错误.这是不正确的.

对于可由多个线程访问的每个可变状态变量,必须在保持相同锁的情况下执行对该变量的所有访问.在这种情况下,我们说该变量由该锁保护.

在没有同步的情况下,编译器,处理器和运行时可以对操作看起来执行的顺序做一些彻头彻尾的奇怪事情.尝试推断在不充分同步的多线程程序中"必须"发生内存操作的顺序几乎肯定是不正确的.

通常情况下,您不必非常小心原语,所以如果这是一个int或者boolean它可能是这样:

当一个线程在没有同步的情况下读取一个变量时,它可能会看到一个陈旧的值,但至少它会看到某个线程实际放置的值而不是某个随机值.

但是,这不适用于64位操作,例如on long或者double如果未声明它们volatile:

Java内存模型要求获取和存储操作是原子操作,但对于非易失性长和双变量,JVM允许将64位读或写视为两个独立的32位操作.如果读取和写入发生在不同的线程中,则可以读取非易失性long并返回一个值的高32位和另一个值的低32位.

因此,即使您不关心陈旧值,在多线程程序中使用共享的可变长和双变量也是不安全的,除非它们被声明为volatile或由锁保护.

  • 详细说明,如果想要在多线程应用程序中获取最新版本的值,则应同步getter和setter.如果,出于一些非常奇怪的原因,你不关心获得最新版本,并且同步正在耗费太多时间(这种情况不太可能!)我_think_你没有同步getter就逃之夭夭.除了在这种情况下 - 双精度是64位所以它应该始终是同步的. (7认同)
  • @ user949300不同步getter只是**不正确**.你可能**永远不会**观察到var的变化. (4认同)
  • @user949300 您不仅无法获得最新版本,而且您甚至不知道将获得哪个版本 - 而且该版本可能因一个线程而异。这几乎不是一个可以接受的场景...... (2认同)
  • "在没有同步的情况下,编译器,处理器和运行时可以根据操作似乎执行的顺序执行一些非常奇怪的事情" - 请参阅http:// docs中的示例17.4.5-1(在一致性之前发生) .oracle.com/JavaSE的/规格/ JLS/SE7/HTML/JLS-17.html#JLS-17.4.5 (2认同)
  • @gasan JVM是32位还是64位是无关紧要的,因为我们正在讨论**规范**级别.JLS**指定**`long`和`double`操作为非原子操作.但是,所有这一切与新的内存模型定义完全无关,因为很明显没有正确的'先发生'排序就没有交易. (2认同)

Mar*_*nik 18

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

while (myBean.getValue() > 1.0) {
  // perform some action
  Thread.sleep(1);
}
Run Code Online (Sandbox Code Playgroud)

JIT编译:

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

在稍微不同的场景中,即使Java编译器也可以产生类似的字节码(它只需要消除动态调度到不同的可能性getValue).这是一个提升的教科书例子.

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

  • @gasan每天你都在执行代码,其中完全像这样的东西(有些甚至**更可怕)一直在发生. (3认同)
  • 是否有任何官方消息来源说没有"同步"这样的排列是可能的,并且"同步"排除它们发生? (2认同)