Android 进阶 单例模式

一.单例模式简介

 


顾名思义,单例模式指的是在软件系统运行过程中,某个类只存在一个实例。因此一个类实现单例模式时需要具备以下3个条件:


1)类的内部定义一个该类的静态私有成员变量;


2)构造方法为私有;


 

3)提供静态工厂方法,供外部获取类的实例;

 

 

 

二.单例模式实现方式

 

<1> 饿汉模式

package com.wjn.lubandemo.utils;

public class Singleton {

    private static Singleton INSTANCE = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return INSTANCE;
    }

}

饿汉模式在类被初始化时就已经在内存中创建了对象,以空间换时间,故不存在线程安全问题。

 

 

 

<2> 懒汉模式

package com.wjn.lubandemo.utils;

public class Singleton {

    private static Singleton INSTANCE = null;

    private Singleton() {
        
    }

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }

}

懒汉模式在方法被调用后才创建对象,以时间换空间,在多线程环境下存在风险。

 

 

 

<3> 双重锁懒汉模式(Double Check Lock)

package com.wjn.lubandemo.utils;

public class Singleton {

    private static Singleton INSTANCE = null;

    private Singleton() {
        
    }

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

 

DCL模式的优点就是,只有在对象需要被使用时才创建,第一次判断 INSTANCE == null为了避免非必要加锁,当第一次加载时才对实例进行加锁再实例化。这样既可以节约内存空间,又可以保证线程安全。但是,由于jvm存在乱序执行功能,DCL也会出现线程不安全的情况。具体分析如下:

 

INSTANCE  = new SingleTon(); 

 

这个步骤,其实在jvm里面的执行分为三步:

  1.在堆内存开辟内存空间。
  2.在堆内存中实例化SingleTon里面的各个参数。
  3.把对象指向堆内存空间。

由于jvm存在乱序执行功能,所以可能在2还没执行时就先执行了3,如果此时再被切换到线程B上,由于执行了3,INSTANCE 已经非空了,会被直接拿出来用,这样的话,就会出现异常。这个就是著名的DCL失效问题。

不过在JDK1.5之后,官方也发现了这个问题,故而具体化了volatile,即在JDK1.6及以后,只要定义为private volatile static SingleTon  INSTANCE = null;就可解决DCL失效问题。volatile确保INSTANCE每次均在主内存中读取,这样虽然会牺牲一点效率,但也无伤大雅。

 

 

 

<4>静态内部类模式

package com.wjn.lubandemo.utils;

public class Singleton {

    private Singleton() {
        
    }

    private static class SingleTonHoler {
        private static Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingleTonHoler.INSTANCE;
    }
}

 

静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。即当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

 

你可能感兴趣的:(Android,进阶)