单例模式几种写法

1.饿汉式

public class SingletonInstance {
    //私有构造方法
    private static SingletonInstance (){

    }
    //声明成员变量
    private static SingletonInstance singletonInstance = new SingletonInstance();
    //对外提供接口获取该实例
    public static SingletonInstance getSingletonInstance(){
        return singletonInstance ;
    }

}

2.懒汉式

public class SingletonInstance {
    //私有构造方法
    private SingletonInstance (){

    }
    //声明成员变量
    private static SingletonInstance singletonInstance ;
    //对外提供接口获取该实例
    public static SingletonInstance getSingletonInstance(){
        if(singletonInstance == null){
            singletonInstance = new SingletonInstance();
        }
        return singletonInstance ;
    }

}

 

饿汉式 懒汉式是经典的单例写法,但是线程不安全,当然,为保证线程安全,可以对getSingletonInstance()函数加锁,如下:

 public static synchronized SingletonInstance getSingletonInstance(){
        return singletonInstance = new SingletonInstance();
    }

但是这样每次获取单例都会判断锁,会很消耗资源,所以饿汉式和懒汉式不推荐使用,推荐使用以下方式

3.double check lock(dcl)

public class SingletonInstance {
    //私有构造方法
    private SingletonInstance (){

    }
    //声明成员变量
    private static SingletonInstance singletonInstance ;
    //对外提供接口获取该实例
    public static SingletonInstance getSingletonInstance(){
        if(singletonInstance == null){
            synchronized (SingletonInstance.class){
                //两次判断是否为null
                if(singletonInstance==null){
                    singletonInstance = new SingletonInstance();
                }
            }
        }
        return singletonInstance ;
    }

}

DCl 资源利用率高,执行效率也高,缺点是第一次加载的时候会比较慢,而且在高并发的时候,有可能会导致单例不成功(概率很小),推荐使用这种方式

4.静态内部类

public class SingletonInstance {
    //私有构造方法
    private SingletonInstance (){

    }
    
    private static class Builder{
        //声明成员变量
        private static SingletonInstance singletonInstance = new SingletonInstance();
    }
    //对外提供接口获取该实例
    public static SingletonInstance getSingletonInstance(){
        return Builder.singletonInstance ;
    }

}

这种方法,实例只会被创建一次,而且只有在被引用的时候创建,线程安全也能保证,所以推荐使用这种方式

5.以上四种方法,不管哪种方法,在反序列化的时候,都不能保证单例。但是使用枚举可以避免这个问题,枚举默认就是线程安全的

public enum Singleton {  //enum枚举类
    INSTANCE;  
}

但是枚举在android中是不建议使用的,因为枚举比constants消耗更大的内存,

6.单例管理类创建单例

public class SingletonManager { 
  private static Map<String, Object> objMap = new HashMap<String,Object>();//使用HashMap作为缓存容器
  private Singleton() { 
  }
  public static void registerService(String key, Objectinstance) {
    if (!objMap.containsKey(key) ) {
      objMap.put(key, instance) ;//第一次是存入Map
    }
  }
  public static ObjectgetService(String key) {
    return objMap.get(key) ;//返回与key相对应的对象
  }
}

7.反序列化杜绝生成新的实例,需要加入以下这个函数

private Object readResolve()  throws ObjectStreamException{
    return INSTANCE;
}

 

posted @ 2018-01-09 14:19  贺长寿  阅读(3328)  评论(0编辑  收藏  举报