了解初始安全性

时间:2016-05-05 08:21:59

标签: java multithreading

B中。 Goetz在他的JCIP第16.3章中写道:

  

初始化安全意味着清单16.8中的SafeStates可能是   甚至通过不安全的懒惰初始化或存储安全发布   在没有公共静态字段的情况下引用SafeStates   同步[...]

代码:

@ThreadSafe
public class SafeStates {
    private final Map<String, String> states;

    public SafeStates(){
        states = new HashMap<String, String>();
        states.put("alaska", "AK");
        states.put("alabama", "AL");
        ...
        states.put("wyoming", "WY");
    }

    public String getAbbreviation(String s){
        return states.fet(s);
    }
}

不安全的延迟初始化

@NotThreadSafe
public class UnsafeLazyInitialization{ 
    private static Resource resource;

    public static Resource getInstance(){
        if(resource == null)
            resource = new Resource();
        return resource;
    }
}

我不明白为什么以这种方式发布对象是安全的。 resource引用不是volatile,因此即使happens-before是不可变的,在写入它(resource = new Resource())和后续读取之间也没有Resource。< / p>

这样,任何未初始化resource的线程都可能会观察到resource陈旧值

3 个答案:

答案 0 :(得分:2)

The UnsafeLazyInitialization is unsafe because one thread may set value of the resource before constructor of Resource is fully completed, so another thread will pick a reference to a partly initialised object.

答案 1 :(得分:0)

如果我正确理解这个问题,那就不是为什么@NotThreadSafe示例不安全或为什么@ThreadSafe示例安全。

这就是为什么两者的结合是安全的,即为什么以下是安全的:

public class UnsafeLazyInitialization{ 
    private static SafeStates safeStates;

    public static SafeStates getInstance(){
        if (safeStates == null)
            safeStates = new SafeStates();
        return safeStates;
    }
}

答案是,如果正在初始化单个final字段,则构造函数末尾会出现“冻结操作”。该操作(您可以将其设想为StoreStore屏障)可确保如果您看到非null实例,则该实例将完全初始化。请记住,这并不意味着您无法观察到null实例(实例读取仍然是活泼的)。

有关更多信息,请查看Aleksey Shipilev撰写的这篇精彩博文:Safe Publication and Safe Initialization in Java

答案 2 :(得分:-2)

不同之处在于,不安全代码中存在&#34;静态&#34; 。 静态意味着&#34;资源&#34; object是 class 对象,而不是实例对象。