单例模式的几种实现方式总结

2018-03-25  本文已影响20人  RenHaiRenWjc

单例模式

  1. 是什么?
    确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

  2. 使用场景?
    如访问IO和数据库等资源,创建一个对象需要消耗的资源过多,适合使用单例模式,确保某个类有且只有一个对象。

  3. 关键点
    a. 构造函数不对外开放,一般为 Private
    b. 通过一个静态方法返回单例类对象
    c.确保单例类的对象有且仅只有一个,尤其是在多线程环境下(线程安全)
    d.确保单例类对象在反序列时不会重新构造对象

  4. 示例

a. 饿汉单例模式
a0:static变量只会在类装载的时候初始化一次,并且多个实例共享内存区域,非常符合单例的需求
a1:重点就在于饿,一饿就急就会急着用,没有访问也创建对象

public class MyClass {
    private static final MyClass mMyClass = new MyClass();

    private MyClass() { }
    public static MyClass getMyClass(){
        return mMyClass;
    }
}

b. 懒汉模式
b0:只有在使用时才会被实例化
b1:每次调用 getInstance都进行同步,造成不必要的同步开销,一般不建议用

public class MyClass {
    private static MyClass instance;

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

c. Double Check Lock(DCL)实现单例
c0:能够在需要时才初始化单例,又能够保证线程安全,且单例对象初始化后调用 getInstance 不进行同步锁,资源利用率高,效率高。
c1:第一次加载有点稍慢;由于Java内存模型的原因偶尔失败。
使用最多的单例实现方式

public class MyClass {
    private static MyClass instance = null;

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

d. 静态内部类单例模式
第一次调用 getInstance 才会导致虚拟机加载SingletonHolder类,这不仅能确保线程安全,而且能够保证单例对象的唯一性,同时也是延迟了单例的实例化。
推荐使用

public class MyClass {
    private MyClass() {}

    public static MyClass getInstance() {
        return SingletonHolder.sInstance;
    }

    private static class SingletonHolder {
        private static final MyClass sInstance = new MyClass();
    }
}

e.枚举单例
默认的枚举实例的创建时线程安全的,并且在任何一种情况都是单例
以上几种单例实现,在反序列化时,会出现重新创建对象的情况。

public enum SingletonEnum {
    INSTANCE;
    public void doSomething(){
        
    }
}

(完)

上一篇下一篇

猜你喜欢

热点阅读