单例模式

来源:互联网 发布:博罗县网络问政 编辑:程序博客网 时间:2024/06/02 05:24

最近想把设计模式和Android源码的东西梳理一下,所以会写一些笔记来记录这些东西。

单例模式简介

单例模式用来保证单例对象的类只有一个对象实例存在。当一个应用中的一个对象的创建很消耗资源的时候,我们就会保存一个单例实例。这时就可以使用单例模式了。

单例模式的定义

确保某一个类只有一个实例,而且自行实例话并向整个系统提供这个实例

单例模式的实现方式

懒汉模式

懒汉模式声明一个静态对象,并且在用户第一次调用的时候进行初始化。实现如下:

public class Singleton {    private static Singleton mInstance;    private Singleton(){}    public static synchronized Singleton getInstance(){        if(mInstance == null){            mInstance = new Singleton();        }        return mInstance;    }}

通过把构造声明为私有,并且getInstance方法添加synchronized关键字保证同步而只有一个实例对象创建。这种实现如果在实际使用过程中每次获取这个对象都要经过同步的方法来获取会很消耗资源。

Double Check Lock实现单例

这种方式来实现单例是我们在开发中常用的一种方式。代码如下:

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

这种方式在方式一的基础上的改良版本,我们看到有两个判空的代码,第一个为了避免不必要的同步,第二个为了在实例为空的时候创建实例。因为这几行代码不是一个原子的操作。把这个过程划分为如下几个步骤:

  • 给Singleton 的实例分配内存
  • 调用Singleton的构造方法,初始化成员字段
  • 将mInstance 对象指向分配的内存空间

    因为Java编译器允许处理器乱序执行,上面的三个步骤的顺序的第二个和第三个顺序不定,当一个 线程执行为132,当执行到3步骤的时候另一个线程获得CPU执行它会判断mInstance为不为空,这个时候返回的对象还没有初始化成员不是一个完整的对象,所以会出现问题。

    在Jdk1.5之后,sun注意到了这个问题,调整了JVM,具体化了volatile关键字,所以在Jdk1.5之后将mInstance声明为volatile就可以保证mInstance对象都是从主内存中读取。

    DCL优点:
    资源利用率高,第一次执行getInstance的时候才会实例化对象效率高。
    DCL缺点
    第一次加载反应稍慢,也可能由于Java内存模型创建使用失败。

除非使用低于JDK6的版本,否则这种方式是使用较多的一种方式。

静态内部类实现单例

这是一种更加优于DCL的一种方案。

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

第一次加载Singleton类时并不会初始化mInstance实例,只有在调用getInstance方法的时候会加载SingletonHolder类。这种方式保证了线程安全和唯一性,也延迟了单例的实例化。

原创粉丝点击