在构建了一个对象之后,是否与其他线程建立了内存围栏



有人能验证我对构造函数执行后建立的内存围栏的理解吗。例如,假设我有一个名为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()updatePrice()Thread2多次调用(始终由Thread2调用)。

我的论点是,在Thread1创建对象之后,对象的"可见性"与jvm中的所有其他线程一起建立。由于这两个可变变量只由Thread2更改,所以我不需要任何锁定。我说得对吗?

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

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

由于这两个可变变量只由Thread2更改,所以我不需要任何锁定。

Thread2中对对象进行初始同步后,您将不需要任何额外的锁定,除非您希望在其他线程中看到那些突变的字段。如果多个线程正在读取Stock对象,而Thread2正在对其进行更改,则所有线程都需要通过同步或使字段变为volatile来跨越内存屏障。

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

这是对象的安全发布吗?

不幸的是,没有。构造函数(主要)像Java内存模型中的一个普通方法。

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

最新更新