设计模式之单例模式

作者: 我的学长是王欣 | 来源:发表于2016-04-22 19:36 被阅读100次

    什么是设计模式: 被反复使用,代码设计经验的总结

    使用设计模式目的: 代码的重用,让代码更易于理解,保证代码可靠性

    概念

    • 单例对象的类必须保证只有一个实例存在。

    适合场景

    • 整个系统只需要拥有一个的全局对象。

    分类

    • 懒汉式:指全局的单例实例在第一次被使用时构建
    • 饿汉式:指全局的单例实例在类装载时构建
    • 静态内部类: 在静态内部类中声明一个instance

    步骤

    1. 构造器私有化
    2. 创建类的唯一实例,使用private static 修饰
    3. 提供一个获取实例的public方法
    4. enum枚举

    饿汉式(线程安全)

    class Singleton{
      //类加载时创建instance
      private static Singleton instance = new Singleton();
    
      private Singleton(){
      }
    
      public Singleton getInstance(){
        return instance;
      }
    
    }
    

    懒汉式

    class Singleton{
      //仅仅声明instance
      private static Singleton instance ;
    
      private Singleton(){
      }
    
      public Singleton getInstance(){
        if(instance==null){
            instance = new Singleton();
        }
        return instance;
      }
    
    }
    

    上面这种getInstance有致命的缺陷,就是无法保证线程安全。而给整个方法加synchronized效率不高。考虑到同步操作只需要在第一次调用时才被需要,即第一次创建单例实例对象时。这就引出了双重检验锁

    双重检验锁

    是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。

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

    静态内部类

    class Singleton{
      private static class SingletonHolder{//使用私有修饰符
        private static final Singleton instance = new Singleton();
      }
      private Singleton(){}
    
      public static final Singleton getInstance(){
        return SingletonHolder.instance;
      }
    }
    

    这种写法仍然使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。

    枚举

    enum Dog {
        DogA(1, "dog1"),DogB(2,"dog2");//实例
    
        int age;//私有变量
        String name;
    
        Dog(int age, String name) {//构造方法
            this.age = age;
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Dog{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    //调用
    public static void main(String[] args) {
          Dog dog = Dog.DogA;
          System.out.println(dog);
    
      }
    

    总结

    • 4种方式推荐使用后两种,其中枚举最适合,同时也最难理解。

    参考资料

    我的博客

    相关文章

      网友评论

        本文标题:设计模式之单例模式

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