Java单例模式

Java单例模式

单例模式是设计模式中比较简单的模式,当全局只需要一个实例的时候就可以用单例模式。


一、懒汉式

//懒汉式 不安全 单例类 
public class Singleton {  
    private static Singleton single;  
    //静态工厂方法   
    public static Singleton getInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        return single;  
    }  
}

问题:线程不安全。

如何变成线程安全?使用 synchronized,但是这样对效率会有影响。

//懒汉式 线程安全 单例类
public class Singleton {
    private static Singleton instance = null;

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

二、饿汉式

懒汉式在需要的时候才进行初始化,而饿汉式在类加载的时候就初始化了。

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

三、双重锁定

正确的双重锁定需要加 volatile 来禁止指令重排序。

public class Singleton {
    private volatile static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

如果不加 volatile 的话 会有什么问题呢?

singleton = new Singleton(); 可以分解为3步

1.首先jvm要为这个对象实例分配内存空间。
2.初始化这个对象。
3.将instance指向内存地址。

指令重排序后,可能会将3操作放到2前面,因为对于单线程来说,不会影响执行结果。

3和2 对换后,instance 这个时候指向一个未初始化的内存地址。

如果刚好有个线程到达在第一层检测,就会发现不为空,直接走return 语句,而这个时候 instance还未初始化完成。就会出现问题。

而加了 volatile 之后,重排序被禁止,就不会出问题。

四、静态内部类

public class Singleton {
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
    }

    public static final Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

即避免了同步,又可以延迟初始化。

发表评论

电子邮件地址不会被公开。 必填项已用*标注