在构造函数执行后但在返回引用之前调用 setter 是否是安全的发布?
public class SafePublication {
private int i = 0;
private SafePublication() {
i = 10;
}
// Here we are calling setter are object creation.
//Will this change be visible to other threads
public static SafePublication getInstance() {
SafePublication pub = new SafePublication();
pub.setVal(20);
return pub;
}
private void setVal(int x) {
this.i = x;
}
}
最佳答案
不,这不安全。
setVal
方法不是同步的,i
不是易变的。因此,在对 i
的更新(通过 setVal
)与在读取 i
的另一个线程上运行的任何代码之间将没有同步点。 setVal
调用发生在构造实例的线程中这一事实产生了不同。
最重要的是,另一个线程可能将i
的值视为0
、10
中的任何一个> 或 20
。
How may another thread see that value if the reference to the object has not been returned yet?
事实并非如此。问题是其他线程可能看不到i
的正确值。
我认为您将这种情况与字段为 final
的情况混淆了。在那里,JLS 确实指定该字段已安全发布。问题在于此保证不适用于非最终字段;见JLS 17.5 .写法如下:
"An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's
final
fields. "
(强调)
i would rather say another thread may see the value of i as any one of 10 or 20. It is guaranteed not to see 0.
据我所知,JLS 17.4 中没有任何内容或 JLS 17.5提供保证。唯一可以保证的是,在默认初始化发生之前,没有人会看到 i
的值。 (请随意证明我错了......引用 JLS。)
关于java - 在对象上调用 setter 后安全发布 Java 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14120712/