学习笔记

Android源码设计模式_2单例模式
Publish: 2018/8/10   

定义

确保某一个类只有一个实例,二期自行实例化并向整个系统提供这个实例。

实现单例模式的几个关键点

饿汉式

 public class CEO{
     private static final CEO mCeo = new CEO();

     private CEO(){}

     public static CEO getCeo(){
         return mCeo;
     }

     public void doSomething(){}
 }

饿汉式

方式一

 public class Singleton{
     private static Singleton instance;
     private Singleton(){}

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

缺点:即使instance已经被初始化,每次调用getInstance方法都会进行同步,这样会消耗不必要的资源。

方式二:双重锁校验

 public class Singleton{
     private static Singleton instance;
     private Singleton(){}

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

缺点:instance = new Singleton();语句并不是一个原子操作,大致做了3件事情:

  1. 给Singleton的实例分配内存。
  2. 调用Singleton的构造函数,初始化成员字段。
  3. 将instance对象指向分配的内存空间(此时instance就不是null了)。

由于Java编译器底层优化,执行完1,2和3的顺序时无法保证的。如果3执行完,2未执行前,被切换到B上,这时候instance因为已经在线程A内执行过3,instance已经是非空了,所以,线程B直接取走了instance,再使用时就会出错。只需要将instance的定义改成private volatile static Singleton instance = null;就可以保证instance对象每次都从主内存中读取。

方式三:推荐方式静态内部类

 public class Singleton{
     private Singleton(){}
     public static Singleton getInstance(){
         return SingletonHolder.sInstance;
     }

     /** 
      * 静态内部类
      */
     private static class SingletonHolder{
         private static final Singleton sInstance = new Singleton();
     }
 }

当第一次加载Singleton类时并不会初始化sInstance,只有在第一次调用Singleton的getInstance方法时才会导致sInstance被初始化。这是推荐使用的单例模式实现方式。

方式四:最佳方式枚举单例

 public enum SingletonEnum{
     INSTANCE;
     public void doSomething(){}
 }

默认枚举实例的创建时线程安全的,并且在任何情况下它都是一个单例。枚举不存在反序列化生成新的实例。之前的方式要杜绝单例对象在反序列化时重新生成对象,必须加入如下方法:

 //在反序列化提供的钩子函数中将mInstance对象返回。
 private Object readResolve() throws ObjectStreamException{
     return mInstance;
 }

方式五:使用容器实现单例

 public class SingletonManager{
     private static Map<String,Object> objMap = new HashMap();

     private SingletonManager(){}
     public static void registerService(String key,Object instance){
         if(!objMap.containsKey(key)){
             objMap.put(key,instance);
         }
     }

     public static Object getService(String key){
         return objMap.get(key);
     }
 }


← Android源码设计模式_3原型模式 Android源码设计模式_1面向对象的六大原则 →

Powered by Hexo, Theme designs by @hpcslag.
Style-Framework Tocas-UI designs by @yamioldmel