单例模式
单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。
单例模式结构图.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()方法没有任何线程锁定,因此其性能不会造成任何影响。