1./* 安全的方式  */  
2.public class Singleton {   
3.  
4.  private static Singleton instance = new Singleton();   
5.  
6.  private Singleton() {}   
7.  
8.  public static Singleton getInstance() {   
9.    return instance;   
10.  }   
11.  
12.} /*非线程安全的方式*/
1.public class Singleton {   
2.       
3.    private Singleton() {}   
4.    private static Singleton instance = null;   
5.  
6.    public static Singleton getInstance() {   
7.        if(instance == null) {   
8.            instance = new Singleton();   
9.        }   
10.        return instance;   
11.    }   
12.}  
 我看到解释如下:第一种方式虽然没有使用同步,但确保了调用static getInstance()方法时才创建Singleton的引用(static 的成员变量在一个类中只有一份)。
---------------------------
我不理解的是,为何说是“调用static getInstance()方法时才创建Singleton的引用”
不是一开始申明static变量的时候就创建了吗private static Singleton instance = new Singleton();   
按我的理解两种方式申明instance不是一样的么,都是private static的,只是创建时间不一样而已
为何说第一种比第二种安全?忘高手详细解释,指点一下

解决方案 »

  1.   

    第一种形式为啥是线程安全的?
    因为instance是static成员变量,它是在类加载的时候进行初始化的,而jvm的类加载机制保证了只有一个线程会对它进行初始化,绝对不会存在线程安全问题,这是由jvm来保证的。
    第二个为啥不安全?
    就不用说了吧
      

  2.   

    两种方式申明instance不是一样的么,都是private static的呀。
    我的问题是:第一种方式的instance = new Singleton();  这个new操作时在类装载的时候
    就创建么?
      

  3.   

    private static Singleton instance = null;   
    这种方式并没有在类加载的时候就进行初始化。
      

  4.   

    所有的类变量初始化语句和静态代码块都被java编译器收集到一起,放到一个特殊的方法中,对于类来说,这个方法叫做类的初始化方法,对于接口来说,被成为接口初始化方法。在类和接口的java class文件当中,这个方法叫做<clinit>。通常的java程序无法调用这个<clinit>方法,只是被虚拟机来调用,专门用来把静态变量设置为他们的正确的值。并非所有的类都需要在他们的class文件中拥有一个<clinit>()方法,如果类没有声明任何的类变量,也没有任何的静态初始化块,就不会有<clinit>()方法。即使有类变量,但是并没有明确的使用类变量初始化语句或者静态代码块来初始化他们,那么类也不会有<clinit>()方法。只有static final常量表达式的也不会有<clinit>()方法。具体参考:深入java虚拟机
      

  5.   

    确保了调用static getInstance()方法时才创建Singleton的引用是针对第二种方式而言的,因为第二种方式在调用getInstance()时,当instance是null时才会创建实例,而很有可能是多个线程同时进入getInstance方法,所以可能instance会被多次new,这样就不能保证安全。而第一种方式是类加载时JVM就自动载入,所以其他线程是没有机会再对instance new一次的