1

在构造函数执行之后但在返回引用之前调用 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;
   }
}
4

1 回答 1

3

不,不会安全的。

setVal方法不是同步的,i也不是易失的。因此,对i(via setVal) 的更新与在另一个读取i. setVal调用发生在构造实例的线程中的事实有所不同。

底线是另一个线程可能会将的值视为或中的i任何一个。01020


如果对对象的引用还没有返回,另一个线程如何看到该值?

它不是。问题是其他线程可能看不到i.

我认为您将这种情况与该字段的情况混淆了final。在那里,JLS确实指定该字段是安全发布的。问题是这种保证不适用于非最终字段;见JLS 17.5。措辞如下:

“当一个对象的构造函数完成时,它被认为是完全初始化的。只有在对象完全初始化后才能看到对该对象的引用的线程保证能看到该对象final字段的正确初始化值。”

(重点补充)


我宁愿说另一个线程可能会将 i 的值视为 10 或 20 中的任何一个。保证不会看到 0。

AFAIK, JLS 17.4JLS 17.5中没有任何东西可以提供这种保证。唯一可以保证的是,i在默认初始化发生之前,什么都不会看到 的值。(请随时证明我错了……参考 JLS。)

于 2013-01-02T11:08:55.240 回答