美文网首页
单例模式学习总结

单例模式学习总结

作者: ting723 | 来源:发表于2015-08-13 22:29 被阅读587次
    1. 定义
      • 保证一个类仅有一个实例,并提供一个访问它的全局访问点——《设计模式》
        * 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例
        * 单例模式是通过private限定,避免了类在外部被实例化
        * 通过Java反射机制是能够实例化构造方法为private的类的,这基本会所有的java单例实现失效,故使用单例默认是指不使用反射的情况

    2. 特点
      • 单例类只能有一个实例或给定数目的单例
      • 单例类必须自己创建自己的唯一实例
      • 单例类必须给所有其他对象提供这个实例
    3. 分类
      • 常见的分为饿汉模式和懒汉模式
      • 还有其他的如登记式单例模式,枚举,双重校验锁,内部静态类等
      • 有个牛人一下总结了七种单例模式:具体参考单例模式的七种写法
      • 单例模式的扩展:有上限的多例模式
    4. 优点
      • 避免对资源的多重占用,避免对同一个资源文件的同时操作,造成文件状态不一致
      • 减少内存开支,尤其是需要频繁创建和使用的类
      • 对象创建需要较多资源时,使用单例模式,可以减少系统开销
      • 设置全局访问点,优化和共享资源访问
    5. 缺点
      • 没有接口,不能扩展
      • 单例类的职责过重,在一定程度上违反了"单一职责原则"
    6. 单例模式的使用场景
      • 具有资源管理器功能的应用:线程池,缓存,日志,对话,打印机等
      • 整个项目中需要一个共享访问带点或共享数据
      • 创建一个对象需要消耗的资源过多,如访问IO和数据库等资源
      • 需要定义大量的静态常量和静态方法的环境,可以采用单例模式(或直接采用static)
      • 多个对象可能会造成影响等
      • 对系统资源的使用有限定
    7. 示例
      • 饿汉模式
          //一般情况下,推荐使用这种单例,在类加载时,就开始实例化,线程安全,不能延迟加载
          public class Singleton{
              private static final Singleton instance = new Singleton();
              private Singleton(){}
              private static Singleton getInstance(){
                  return instance;
              }
          }
      
      • "变种"饿汉
          //
          public class Singleton{
              private static Singleton instance = null;
              static{
                  instance = new Singleton(); 
              }
              private Singleton(){}
              public static Singleton getInstance(){
                  return this.instance; 
              }
          }
      
      • 懒汉模式
          public class Singleton{
              private static Singleton instance = null;
              private Singeton(){}
              //线程安全的,并可以很好地延迟加载,但效率很低
              //private static synchronized Singleton getInstance()
              //线程不安全,可以延迟加载,但多线程下工作不能正常工作,不建议使用
              public static Singleton getInstance(){
                  if(instance==null){
                      instance = new Singleton();
                  }
                  return  instance;
              }
          }
      
      • 静态内部类
          //利用了classloder的机制来保证初始化instance时只有一个线程
          //Singleton类加载时,SingleHolder并没有加载,在调用getInstance()才开始加载,实现延迟加载的目的
          public class Singleton{
              private static class SingleHolder{
                  public static final Singleton INSTANCE = new Singleton();
              }
              private Singleton(){}
              private static final getInstance(){
                  return SingleHolder.INSTANCE;
              }
          }
      
      • 枚举
          //能避免多线程同步问题,还能防止反序列化重新创建新的对象
          public enum Singleton{
              INSTANCE;
              public void whateverMethod(){
              }
          }
      
      • 双重校验锁
          // 线程安全,运行效率低,不建议大量采用
          public class Singleton {
              //volatile 关键字:被volatile修饰的变量的值,不会被本地线程缓存,所有对该变量的读写都是直接操作内存,从而确保多个线程能正确处理该变量
              private volatile static Singleton singleton=null;
              private Singleton(){}
              public static Singleton getSingleton(){
                  if(singleton==null){
                      //同步锁
                      synchronized(Singleton.class){
                          if(singleton==null){
                              singleton = new Singleton();
                          }
                      }
                  }
              }
              return singleton;
          }
      
      • 登记式单例模式
          //登记式实际对一组单例模式进行的维护,即对多个单例类进行维护,主要是在数量上的扩展
          //通过map我们把单例存进去,这样在调用时,先判断该单例是否已经创建,是的话直接返回,不是的话创建一个登记到map中,在返回
          // 对于数量分为固定数量和不固定数量
          public class Singleton {
              private static Map<String,Singleton> map = new HashMap<String,Singleton>();
              static{
                  Singleton instance = new Singleton();
                  map.put(single.getClass.getName(),instance);
              }
              private Singleton(){}
              public static Singleton getInstance(String name){
                  if(name = null){
                      name = Singleton.class.getName();
                  }
                  if(map.get(name)==null){
                     try{
                        map.put(name,(Singleton)Class.forName(name).newInstance());
                     }catch(InstantitionException e){
                        e.printStackTrace();
                     }catch(IllegallAccessException e){
                        e.printStackTrace();
                     }catch (ClassNotFoundException e) {
      

    27 e.printStackTrace();
    28 }
    }
    return map.get(name);
    }
    }
    ```
    * 总结
    * 其中饿汉静态内部这两种方式比较易用,简单易懂,且线程安全
    * 在没有明确要求延迟加载的情况下,推荐使用饿汉模式
    * 明确要求延迟加载,则推荐使用静态内部类
    * 懒汉模式不建议使用,即使使用了synchronized,保证了线程安全,但加载速度也会很慢

    1. 参考

    相关文章

      网友评论

          本文标题:单例模式学习总结

          本文链接:https://www.haomeiwen.com/subject/yaumqttx.html