单例模式

单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。

单例模式_第1张图片
单例模式结构图.jpg
  • Singleton(单例)

在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

但是这样写,并不能满足只生成一个实例的要求。如果 Singleton的构造方法中需要执行耗时操作,那么当第二次调用getInstance时,为null的条件依然成立,所以会产生多个实例。

以下是两个优化过后的单例模式

  • 饿汉式单例模式
class EagerSingleton {   
    private static final EagerSingleton instance = new EagerSingleton();   
    private EagerSingleton() { }   
  
    public static EagerSingleton getInstance() {  
        return instance;   
    }     
} 

当类被加载时,静态的私有成员变量 instance 就被初始化,并且只会创建一次,不会产生多个实例。

  • 懒汉式单例模式
class LazySingleton {   
    private volatile static LazySingleton instance = null;   
  
    private LazySingleton() { }   
  
    public static LazySingleton getInstance() {   
        //第一重判断  
        if (instance == null) {  
            //锁定代码块  
            synchronized (LazySingleton.class) {  
                //第二重判断  
                if (instance == null) {  
                    instance = new LazySingleton(); //创建单例实例  
                }  
            }  
        }  
        return instance;   
    }  
}  

依靠synchronized关键字锁定代码块,来确保多线程调用情况下的安全性,也不会产生多个实例。

  • 饿汉式单例在类被加载的时候就实例化了自己,确保了唯一性,也不用考虑多线程访问的问题。但是不管系统是否需要该实例对象,都会创建。且在系统刚加载的时候,时间会增加。

  • 懒汉式单例在第一次需要使用的时候才会创建实例,因此不会浪费系统资源,并且通过双重检查锁,volatile 等关键字来控制,会影响系统性能。

  • java语言最好的单例模式写法 Initialization Demand Holder (IoDH)
//Initialization on Demand Holder  
class Singleton {  
    private Singleton() {  
    }  
      
    private static class HolderClass {  
            private final static Singleton instance = new Singleton();  
    }  
      
    public static Singleton getInstance() {  
        return HolderClass.instance;  
    }  
}  

由于静态单例对象没有作为Singleton的成员变量直接实例化,因此类加载时不会实例化Singleton,第一次调用getInstance()时将加载内部类HolderClass,在该内部类中定义了一个static类型的变量instance,此时会首先初始化这个成员变量,由Java虚拟机来保证其线程安全性,确保该成员变量只能初始化一次。由于getInstance()方法没有任何线程锁定,因此其性能不会造成任何影响。

你可能感兴趣的:(单例模式)