单例模式简介

在软件开发中常常有这样一种情景,那就是整个系统中共享着一个唯一的对象。无论是哪个客户端来获取,获取到的对象都是同一个。单例模式就是为这种情景所设计的。单例的创建一般来说有两种方式,饿汉模式和懒汉模式。饿汉模式是当系统一启动就马上创建这个单例供调用者使用。懒汉模式是当系统启动时不创建单例,而当被第一次调用时再进行创建。单例模式还有一个特殊的方案。这种方案使用了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.");
    }
}

(完)