设计模式之单例模式

单例模式

单例模式是应用最广的模式。在某些状态下,需要某个对象需要仅保持一个实例的存在。例如在ImageLoader中,需要保持缓存,线程池等的唯一,这时候就需要用到单例。

实现单例一般有四种。

  • 饿汉式
  • 懒汉式
  • 双重锁模式
  • 内部类模式

饿汉式


class Singleton{
    private static Singleton instance = new Singleton;

    private Singleton(){

    }

    private static Singleton getInstance(){
        return instance;
    }

}

饿汉式是在类加载的时候就创建唯一的类对象。即使未调用getInstance(),仍会创建对象。资源比较浪费。

懒汉式

懒汉式是在需要时在创建唯一的类对象。

class Singleton{

    private static Singleton instance = null;

    private Singleton(){

    }

    private static synchronized Singleton getInstance(){
        if(instance==null){
            instance = new Singleton();
        }

        return instance;

    }


}

懒汉式相比较饿汉式而言,虽然解决了资源浪费的问题,但仍存在一个问题,就是当调用getInstance()方法时,当instance不为null时,仍会因为线程同步而导致资源被浪费,这也是最大的问题。

优点:

  • 只有在资源需要被使用时才会被实例化,这在一定程度上也会解决资源浪费的问题。

缺点:

  • 第一次加载时需要及时加载实例化,反应稍慢。最大的问题是调用getInstance()时,会造成不必要的同步开销。

双重锁模式

双重锁模式( Double CheckLock) - > DCL模式

class Singleton{

    private static Singleton instance = null;

    private Singleton(){

    }

    private static  Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance==null){
                    instance = new Singleton();

                }

            }

        }

        return instance;

    }


}

该方法的特点就是在判断instance==null 的时候判断了两次,很大程度上的解决了同步开销浪费的问题。

  • 第一层判断是为了避免不必要的同步问题。

  • 第二层判断是为了在null的时候创建单例实例。

但该方法的的主要问题如下:

对于instance = new Singleton();这条语句中,在实际的JVM执行中会分成三个步骤进行执行

  1. 给singleton的实例分配内存。
  2. 调用Singleton的构造方法,初始化成员字段。
  3. 将instance指向所分配的内存空间。

在实际的运行中,因为其执行是乱序的,所以无法保证2和3的执行的先后顺序。则会出现如下情况,出现如下运行顺序,即运行1,3,2.则假设运行到3时,突然有线程B调用getInstance()。因为此时程序已经调用了3方法,instance不为null,则线程B直接返回了instance对象,此时程序会出现问题。

该方法能够在需要的时候实例化对象,并且能够在绝大多数场景下保证单例对象的唯一性,除非你的代码能够在并发场景比较复杂或者低于JDK 6版本使用,否则这种方式一般能够满足需求。 —引用自《Android源码设计模式解析与实战》

内部类模式


class Singleton{

    private Singleton(){

    }

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


    private static Singleton getInstance(){

        return SingletonHolder.instance;
    }
}

对于该方法,在不调用getInstance()方法时,SingletonHolder不会被加载,当我们调用时,才会使sintance实例化。那么,即当我们第一次创建调用getInstance()时,对象才会被加载,。该方式不仅能够确保线程安全,也能够保证单例对象的唯一性,同时也延迟了单例的实例化。

此种方式最为推荐

你可能感兴趣的:(设计模式,Singleton,内部类,懒汉式,饿汉式)