设计模式:单例模式
单例模式简介
在软件开发中常常有这样一种情景,那就是整个系统中共享着一个唯一的对象。无论是哪个客户端来获取,获取到的对象都是同一个。单例模式就是为这种情景所设计的。单例的创建一般来说有两种方式,饿汉模式和懒汉模式。饿汉模式是当系统一启动就马上创建这个单例供调用者使用。懒汉模式是当系统启动时不创建单例,而当被第一次调用时再进行创建。单例模式还有一个特殊的方案。这种方案使用了Initialization Demand Holder
(IoDH)技术。这种方式跟语言特性有关。而Java语言具备了这种特性。单例模式只能在类内部创建单例对象,不能在外部进行new
操作,不然就失去了单例的意义。因此,在单例模式中构造方法应该封装为private
。
饿汉模式
饿汉模式的代码比较简单,如EagerSingleton.java
public class EagerSingleton{
private EagerSingleton(){}//把构造方法封装成private
public static EagerSingleton instance = new EagerSingleton();//一开始就创建单例对象
public static EagerSingleton getInstance(){//使用静态方法获取单例对象
return instance;
}
public void display(){
System.out.println("EagerSingleton");
}
}
这个方式是线程安全的,不会产生多个单例对象。因为在类被加载时被创建了对象,而Java底层保证了对象的唯一性。
但是这种方式有个缺点,那就是如果这个单例对象永远不被调用,那么就白白损耗了创建这个对象所花费的性能。于是有了另外一种模式,懒汉模式。
懒汉模式
懒汉模式例子:LazySingleton.java
public class LazySingleton{
public volatile static LazySingleton instance = null;//使用volatile关键字保证多个线程操作时也没有影响
private LazySingleton(){}
public static LazySingleton getInstance(){
if(instance == null){//第一重判断
synchronized(LazySingleton.class){
if(instance == null){//第二重判断
instance = new LazySingleton();
}
}
}
return instance;
}
public void display(){
System.out.println("LazySingleton");
}
}
懒汉模式是第一次调用的时候才进行单例对象的创建。在高并发的情景下有可能同时有多个线程去调用。比如A线程和B线程同时去调用。这时就可能会产生多个单例对象。于是在调用时需要进行判断是否已创建,引入synchronized
后还需要进行二次判断,因为A,B两个线程同时调用的话,A创建了单例对象后,B没有知晓,会继续创建一个对象。引入volatile
保证了两次判断的是同一个对象。
懒汉模式虽然解决了饿汉模式的问题。但是当多个线程同时首次访问时在性能上还是有所影响。而IoDH
技术会解决这个问题。
IoDH技术
这种模式使用静态内部类来创建单例对象,当调用静态单例方法时,静态内部类才会被加载,对象创建的唯一性交由Java底层处理。
IoDHSingleton.java
public class IoDHSingleton{
private IoDHSingleton(){}
private static class HolderClass{
private final static IoDHSingleton instance = new IoDHSingleton();
}
public static IoDHSingleton getInstance(){
return HolderClass.instance;
}
public void display(){
System.out.println("IoDHSingleton.");
}
}
(完)