Android 设计模式之单例实现方式

来源:互联网 发布:请各位知悉还是悉知 编辑:程序博客网 时间:2024/06/05 18:29

原文连接:http://blog.csdn.net/wzgiceman/article/details/51809985


单例的实现方式

Java单例模式可能是最简单也是最常用的设计模式,一个完美的单例需要做到哪些事呢?

  1. 线程安全
  2. 性能
  3. 防止序列化产生新对象
  4. 防止反射攻击

方式一:

public enum Singleton{    INSTANCE;}

优势:

  1. 利用的枚举的特性实现单例
  2. 由JVM保证线程安全
  3. 序列化和反射攻击已经被枚举解决

方式二:

public class Singleton {    private static final Singleton INSTANCE = new Singleton();    private Singleton(){}    public static Singleton getInstance(){        return INSTANCE;    }}

实现Serializable接口需要重写readResolve方法并return INSTANCE,才能保证其反序列化依旧是单例

方式三:

public class Singleton {    private volatile static Singleton INSTANCE;     private Singleton (){}    public static Singleton getSingleton() {        if (INSTANCE == null) {            synchronized (Singleton.class) {                if (INSTANCE == null) {                    INSTANCE = new Singleton();                }            }        }        return INSTANCE;    }}

使用 volatile 的主要原因是其另一个特性:禁止指令重排序优化。也就是说,在 volatile 变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。比如上面的例子,取操作必须在执行完 1-2-3 之后或者 1-3-2 之后,不存在执行到 1-3 然后取到值的情况。从「先行发生原则」的角度理解的话,就是对于一个 volatile 变量的写操作都先行发生于后面对这个变量的读操作(这里的“后面”是时间上的先后顺序)。

但是特别注意在 Java 5 以前的版本使用了 volatile 的双检锁还是有问题的。其原因是 Java 5 以前的 JMM (Java 内存模型)是存在缺陷的,即时将变量声明成 volatile 也不能完全避免重排序,主要是 volatile 变量前后的代码仍然存在重排序问题。这个 volatile 屏蔽重排序的问题在 Java 5 中才得以修复,所以在这之后才可以放心使用 volatile。

方式四:

public class Singleton {    private static class SingletonHolder{        private static final Singleton instance = new Singleton();    }    private Singleton(){    }    public static  Singleton getInstance(){        return SingletonHolder.instance;    }}

使用内部类来维护单例的实例,当Singleton被加载时,其内部类并不会被初始化,故可以确保当 Singleton类被载入JVM时,不会初始化单例类。只有 getInstance() 方法调用时,才会初始化 instance。同时,由于实例的建立是时在类加载时完成,故天生对多线程友好,getInstance() 方法也无需使用同步关键字。


0 0
原创粉丝点击