之前在论坛看到讲解单利模式http://www.cnblogs.com/geek6/articles/3951677.htmljava] view plaincopy
public static Singleton getInstance() {  
        if (instance == null) {  
            synchronized (instance) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  
似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例:a>A、B线程同时进入了第一个if判断b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了
。这里头”new singleton没实例化就出块”这句话有点迷

解决方案 »

  1.   


    因为a线程在执行 instance = new Singleton();  会分配个instance存储地址和初始化2个操作,jvm的优化机制会先分配instance一个内存地址,此时instance不等于null,a线程语句结束完成同步块后,b线程可以进入同步块,此时instance不等于null,但此时instance = new Singleton()由于jvm优化机制中产生异步,a线程中instance初始化还在进行中。 所以b线程因instance非空而跳过了instance初始化语句然后出了同步块,但实际上instance初始化并未完成,这时候如果b线程有使用instance的语句的话会因为初始化还未完成而报错,这里解说的很清楚没什么问题吧?!
      

  2.   

    所以笔者的意思是在多线程情况下,程序运行的复杂性需要充分考虑,最好能明白jvm的运行机制。
      

  3.   

    他的说法应该是错的。 instance = new Singleton();  这一句jvm是在对象初始化后调用完构造函数,然后才会返回,并把Singleton对象地址赋给instance。你可以写个测试代码看看调用顺序:
    public class Main {    static class Test{
            public Test(){
                System.out.println("构造函数");
            }
        }
        public static void main(String[] args) throws Exception {
            Test t = new Test();
            System.out.println("构造返回");
        }
    }
    这段代码的问题不是这个,问题是在synchronized (instance)  这一句,instance是null的话是无法做同步的,如果锁一个非null的对象,这个代码是可以正常运行。但是单例最简单也最方便的,也是我经常用的(他后面的例子还是有点复杂):
     class Singleton{           
            private static Singleton instance = new Singleton();           
            
        public static Singleton getInstance(){           
            return instance;           
        }  
      

  4.   

    顶#3楼. instance 如果是个null , 这个程序有什么意义?