学习设计模式-单例模式自我总结 给自己看的方便记忆。
1.Double Check Lock(DCL) 单例
DCL 方式实现单例模式的优点是既能够在需要时才初始化单例,又能保证线程安全,且单例对象初始化后调用getInstance不进行同步锁。
public class Singleton { private static Singleton mInstance=null; private Singleton(){} public static Singleton getInstance(){ if (mInstance==null){ synchronized (Singleton.class){ if (mInstance==null){ mInstance=new Singleton(); } } } return mInstance; } }
这里解释一下两次判空:第一层判断主要是为了避免不比要的同步,第二层的判断是为了在null的情况下创建实例。
(1)给Singleton的实例分配内存;
(2)调用Singleton()的构造函数,初始化成员字段;
(3)将mInstance对象指向分配的空间(此时mInstance就不是null了);
具体原因是因为 JDK1.5之前 Java编译器允许处理器乱序执行 上面的第二跟第三的顺序是无法保证的。也就是说,执行顺序可能是1-2-3也可能是1-3-2. 如果是后者顺序颠倒 线程会直接取走mInstance 在使用就会出错,这就是DCL失效问题,而且这种错误难以跟踪难以重现 。
优缺点:
DCL的优点:资源利用率高,第一次执行getInstance时单例对象才会被实例化 效率高。
DCL的缺点:第一次加载时反应稍慢,也由于Java内存模型的原因偶尔会失败。在高并发环境下也有一定的缺陷,虽然发生概率很小。
DCL模式是使用最多的单例实现方式,它能在需要时才实例化单例对象,并且能够在绝大多数场景下保证单例对象的唯一性,除非你的代码在并发场景比较复杂或者低于JDK1.6版本下使用,否则这种方式一般能够满足需求。
2.静态内部类单例模式
DCL虽然在一定程度上解决了资源消耗、多余的同步、线程安全等问题,但是它还是在某些情况下出现失效的问题。这个问题被称为双重检查锁定(DCL)失效,在《Java并发编程实践》一书的最后谈到了这个问题,并指出这种“优化”是丑陋的,不赞成使用。
public class Singleton { private Singleton(){} public static Singleton getInstance(){ return SignletonHolder.mInstance; } /** * 静态内部类 */ private static class SignletonHolder{ private static final Singleton mInstance=new Singleton(); } }
当第一次加载Singleton类时并不会初始化mInstance,只有在在第一调用Signleton的getInstance方法是才会导致mInstance被初始化。因此,第一次调用getInstance方法会导致虚拟机加载SingletonHolder类,这种方法不仅能保证线程安全,也能保证单例对象的唯一性,同时也延迟了单例的实例化,所以这是推荐使用的单例模式实现方式。
当然还有一些其他的单例模式 如:枚举单例、使用容器实现单例 这里不做解释。
PS:以上知识点来源于观看的《Android源码设计模式》一书 书写博客为自己总结 方便自己观看 不喜勿喷。