重新理解单例模式

来源:互联网 发布:linux编写c语言 编辑:程序博客网 时间:2024/05/16 06:25

重新理解单例模式

单例模式是设计模式中应用最广的一种设计模式,其核心就是将构造函数私有化,通过静态方法获取一个唯一的实例,当然在这个过程中要保证线程更是安全的。

常用的单例模式有

懒汉模式

public class Vip {    private static Vip mVip=null;    private void Vip() {}    public static synchronized Vip getVip(){        if(mVip==null){            mVip=new Vip();        }        return mVip;    }}

饿汉模式

public class Boss {    private static final Boss mBoss=new Boss();    private void Boss(){    }    public static Boss getBoss(){        return mBoss;    }}

其两种模式的区别就是饿汉模式一个是程序在java虚拟机创建就进行初始化,懒汉模式在首次调用才进行初始化。但是,懒汉模式每次调用都要调用synchronized关键字进行线程同步,造成了不必要的内存开销,反映较慢不推荐使用。从而演变出了DLC (double check lock )从字面意思来看就是双次检查锁定,通过2次空判断来避免懒汉模式中synchronized关键字每次都要进行同步问题。

DLC

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

但是DLC模式有一个问题,上面的代码可以看作在内存进行了如下几部操作
1.分配实例内存
2.调用构造函数,初始化
3.将synchronized对象指向分配的内存空间(这时mVip不为空)
但是,由于java编译器可以乱序执行,1-2-3的顺序当然没问题,但是如果先1-3然后切换到了B线程,由于执行了3 mVip已经不为空却没有初始化,这时候就导致了DLC失效。当然也就解决方法就是加上volatile关键字。变为 private static volatile Vip mVip=null;。DLC可以满足大多数场景的要求,但是由于volatile关键字是java 5.0才出现的所以,DLC出现了驱动力不足,而且这也并不是一种高效的优化措施。

静态内部类单例模式

public class Singleton {    private void Singleton() {    }    public static Singleton getSingleton() {        return SingletonHolder.mSingleton;    }    private static class SingletonHolder {        private static final Singleton mSingleton = new Singleton();    }}

第一次加载Singleton并不会初始化mSingleton只有在第一次调用getSingleton才会导致mSingleton被初始化,因此,第一次调用getSingleton会导致虚拟机加载SingletonHolder类,这种方式不仅可以保证线程安全,也可以保证对象唯一性,同时从代码层面也更加简介,是推荐的单例实现模式。

枚举单例

public enum SingletonEnum {    INSTANCE;    public void doSomething(){//      Log.e("test","test")    }}

因为枚举在java中和普通的类一样不仅可以有字段,还可以有方法,最重要的是枚举默认创建的线程是安全的,且在任何情况下它都是一个单例。但是,上面的几个案例在一种情况下会导致单例重新创建,那就是序列化,在反序列化的时候会导致对象重新创建的情况。如果想杜绝单例模式在反序列化中重新创建的问题就要实现 readResole方法。
private Object readResolve() throws ObjectStreamException{
return mSingleton;
}

容器单例模式

public class SingletonManager {    private static Map<String, Object> objMap = new HashMap<String, Object>();    private SingletonManager() {    }    public static void registerService(String key, Object obj) {        if (!objMap.containsKey(key)) {            objMap.put(key, obj);        }    }    public static Object getService(String key) {        return objMap.get(key);    }}

利用Map的特性可以将多个单例放到一个容器中管理,根据key得到对应的对象

单例在安卓源码中的使用

嗨呀!我也不知道后面怎么写。很乱等我整理出来单独开一章。

原创粉丝点击