单例模式

Singleton-单例模式是确定整个系统中至多只有一个类的实例

第一种:饱汉模式

public class Singleton {
    private Singleton(){}
    private final static Singleton instance = new Singleton();
    public static Singleton getInstance(){
        return instance;
    }
}

注:

(1)private Singleton(){}//私有化类的构造函数,表明这个类无法声明实例对象;

(2)public static Singleton getInstance()...因为私有化了类的构造函数,所以需要提供一个静态的方法提供类的实例;

(3)private final static Singleton instance = new Singleton();饱汉模式下,当这个类被加载的时候,new Singleton() 这句话就会被执行,就算是getInstance()没有被调用,类也被初始化了。这种方式不太好的地方就在于,我们只是希望在真正调用getInstance()方法的时候返回类的对象,而不是依赖于类加载器。

第二种:饥汉模式

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

注:

(1)在方法getInstance()加synchronized控制可以帮我们控制线程同步,但是这样每个线程都要排队来获取,而且哪怕是第一个线程已经把对象创建好了也需要逐个获取类对象,会很影响性能。

(2)改版一,进行Double-Check
public class Singleton{
    private Singleton(){}
    private static Singleton instance = null;
    public static Singleton getInstance() {
        if(instance == null) {
            synchronized(Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

这样的流程是:

  (1)如果实例创建了,则不需要同步直接返回实例;

  (2)如果不存在,则同步线程进行创建;

  (3)返回。

但是这样实现的问题就在于:singleton = new Singleton();,因为创建一个类的实例并不是原子操作的,JVM需要:

  (1)分配内存空间;

  (2)进行类的实例化;

  (3)实例对象指向内存地址,返回(只有返回之后,对象instance才不是null,所以这样就还是会存在问题)

(3)改版二

  将instance声明为volatile,因为被volatile修饰的对象不会在多个线程中同时存在,而是直接从内存中读取。使用volatile关键字声明的变量或对象通常拥有和优化和(或)多线程相关的特殊属性。volatile参考文献

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

 第三种:枚举

public enum Singleton {
  instance;  
}

注:

  默认枚举实例的创建是线程安全的,所以不需要担心线程安全的问题。但是在枚举中的其他任何方法的线程安全由程序员自己负责。还有防止上面的通过反射机制调用私用构造器。

参考文章:

单例模式

深入浅出单实例Singleton设计模式

原文地址:https://www.cnblogs.com/lemon-now/p/5149028.html