单例模式的几种实现方式总结
2018-03-25 本文已影响20人
RenHaiRenWjc
单例模式
-
是什么?
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 -
使用场景?
如访问IO和数据库等资源,创建一个对象需要消耗的资源过多,适合使用单例模式,确保某个类有且只有一个对象。 -
关键点
a. 构造函数不对外开放,一般为 Private
b. 通过一个静态方法返回单例类对象
c.确保单例类的对象有且仅只有一个,尤其是在多线程环境下(线程安全)
d.确保单例类对象在反序列时不会重新构造对象 -
示例
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(){
}
}
(完)