日期:2014-05-20  浏览次数:20580 次

这种singleton实现为什么就是线程安全的呢
摘自:http://en.wikipedia.org/wiki/Singleton_pattern

Java code

public class Singleton {

    // Private constructor prevents instantiation from other classes
    private Singleton() {
        System.out.println("constructor");
    }

    /**
     * SingletonHolder is loaded on the first execution of
     * Singleton.getInstance() or the first access to SingletonHolder.INSTANCE,
     * not before.
     */
    private static class SingletonHolder {
        public static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    
    public static void main(String[] args) {
        System.out.println("main");
        getInstance();
    }

}


上面说:
The nested class is referenced no earlier (and therefore loaded no earlier by the class loader) than the moment that getInstance() is called. Thus, this solution is thread-safe without requiring special language constructs (i.e. volatile or synchronized).

内嵌类在getInstance被调用的时候才被引用到,就保证了它是线程安全的,我想凭什么呢,难道就是因为这个原因吗,就不是因为INSTANCE是final的或其它什么原因? 如果说是因为getInstance的时候才被引用到所以才安全,那意思就是随类一起加载的eager type singleton就不是线程安全的了?据我所知那更是线程安全的啊。而且,这里这个thus是表因果关系,那个“因”感觉有点不靠谱,不知是不是我哪里理解有误~

假设这样一种情景,如果两个线程同时调用getInstance,且同时去初始化下面这句:
public static final Singleton INSTANCE = new Singleton();

那这时候如果它还是线程安全的,又是什么保证的呢



------解决方案--------------------
这段英文的意思是,当getInstance调用时才会加载SingletonHolder类,
而加载SingletonHolder类时会执行public static final Singleton INSTANCE = new Singleton();生成Singleton实例
这个SingletonHolder加载执行是系统控制的,多个线程同时调用getInstance,肯定有某一时刻某个线程先进入getInstance,这时就会自动触发系统加载执行,当其他线程再进入getInstance时,系统加载执行早已结束,所以是线程安全的
其实SingletonHolder没必要



------解决方案--------------------
java的class-loading应该是线程安全的,
如你所说道eager type singleton 就是利用这一点做的,

至于顶楼这样写,我个人觉得应该是一个利用class-loading安全实现lazy type singleton的例子。
如果不通过使用内部类的loading安全实现lazy init,那就需要双重锁或者syncronized方法了
 
------解决方案--------------------
Use this pattern if the initialization of the class is expensive and it cannot be done safely at class-loading time
按理如4楼所说,java spec保证了虚拟机在类加载阶段即class-loading time对于eager type singleton是线程安全的,因为类只加载一次,单例instance也就只会被实例化一次,这里说的不安全会是什么呢,被加载多次吗?这就前后矛盾了,或者实例化会不彻底?要有资料证明才行。