5

有人可以验证我对构造函数执行后建立的内存围栏的理解。例如,假设我有一个名为 Stock 的类。

public final class Stock{

       private final String ticker;
       private double qty;
       private double price;

       public Stock ( String ticker, double qty, double price ){
              this.ticker  = ticker;
              this.qty     = qty;
              this.price   = price;

              //I am assuming a memory fence gets inserted here.
       }


       public final void updateQty( double qty ){
           this.qty = qty;
       }


       public final void updatePrice( double price ){
           this.price = price;
       }

}

此外,假设构造函数由 Thread1 执行updateQty()然后由Thread2updatePrice()调用多次(始终由 Thread2 调用)。

我的论点是,在 Thread1 创建对象之后,对象的“可见性”与 jvm 中的所有其他线程建立起来。而且由于这两个可变变量仅由 Thread2 更改,因此我不需要任何锁定。我对么?

4

2 回答 2

5

我的论点是,在 Thread1 创建对象之后,对象的“可见性”与 jvm 中的所有其他线程建立起来。

这是正确的。没有隐含的构造函数内存屏障/栅栏,这就是为什么围绕构造函数重新排序的指令是这样一个问题。如果要Stock在构造它的线程之外的另一个线程中使用对象,则必须synchronize在调用任何更新方法之前对对象进行处理。

而且由于这两个可变变量仅由 Thread2 更改,因此我不需要任何锁定。

在您最初在对象上同步之后,Thread2您不需要任何额外的锁定,除非您想在其他线程中查看那些变异的字段。Stock如果多个线程在更改对象时从对象中读取数据,Thread2则所有线程都需要通过同步或使字段变为字段来跨越内存屏障volatile

这与构造函数操作重新排序内存可见性有关。有关构造函数重新排序的更多陷阱,请参阅此答案:

这是对象的安全发布吗?

于 2012-10-10T22:53:04.930 回答
1

很不幸的是,不行。构造函数(大部分)类似于 Java 内存模型中的普通方法。

但这很糟糕,它给程序员带来了无尽的困惑。

于 2012-10-10T22:58:04.433 回答