设计模式——单例模式 | 设计模式系列(三)

1,934 阅读2分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战


相关文章

设计模式系列:设计模式


前言

  • 单例模式(Singleton) ,也叫单子模式,是一种常用的设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候,整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,显然,这种方式简化了在复杂环境下的配置管理。
  • 单例模式就是为确保一个类只有一个实例,并为整个系统提供一个全局访问点的一种方法。
  • 平时我们使用的Spring中的Bean默认就是单例的!尤其是javaConfig!

一、饿汉单例

  • //饿汉单例模式
    @Data
    @Accessors(chain = true)
    public class ehanSingleton {
        //其他的属性,举例用的
        private Integer readings = 0;//阅读量
        private Integer collects = 0;//收藏量
        private Integer likes = 0;//点赞量
    ​
        //将自身的实例化对象设置成一个属性,并且加上final,static关键字修饰
        private static final ehanSingleton singleton = new ehanSingleton();
    ​
        //构造方法私有化---外部无法靠new来创建该对象
        private ehanSingleton(){};
    ​
        //公共的静态方法返回该实例,方便外部调用
        public static ehanSingleton getInstance(){
            return singleton;
        }
    }
    
  • TestMain

    • public class SingletonMain {
          public static void main(String[] args) {
              ehanSingleton singleton = ehanSingleton.getInstance();
              singleton.setReadings(singleton.getReadings()+1);
              read(singleton);
              singleton.setCollects(singleton.getCollects()+1);
              singleton.setLikes(singleton.getLikes()+1);
              System.out.println("阅读量为:"+singleton.getReadings());
              System.out.println("收藏量为:"+singleton.getCollects());
              System.out.println("点赞量为:"+singleton.getLikes());
      ​
          }
          public static void read(ehanSingleton singleton){
              for (int i=0;i<100;i++){
                  singleton.setReadings(singleton.getReadings()+1);
              }
          }
      }
      
  • 执行结果

    • image-20211101195643307.png
  • 一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式。

  • 但是问题也比较明显。单例在还没有使用到的时候,初始化就已经完成了。

  • 也就是说,如果程序从头到位都没用使用这个单例的话,单例的对象还是会创建。这就造成了不必要的资源浪费。所以不推荐这种实现方式。

二、懒汉单例

  • //懒汉单例模式
    @Data
    public class lanhanSingleton {
        //其他的属性,举例用的
        private Integer readings = 0;//阅读量
        private Integer collects = 0;//收藏量
        private Integer likes = 0;//点赞量
    ​
        //将自身的实例化对象设置成一个属性,并且加上final,static关键字修饰
        private static lanhanSingleton singleton = null;
    ​
        //构造方法私有化---外部无法靠new来创建该对象
        private lanhanSingleton(){};
    ​
        //公共的静态方法返回该实例,方便外部调用,线程安全的1:同步代码块,效率低
        public static synchronized lanhanSingleton getInstance(){
            if (singleton == null){
                singleton = new lanhanSingleton();
            }
            return singleton;
        }
    ​
        //公共的静态方法返回该实例,方便外部调用,线程安全的2:DCL 双检查锁机制
        public static lanhanSingleton getInstance1(){
            synchronized(lanhanSingleton.class){
                //第一次检查instance是否被实例化出来,如果没有进入if块
                if (singleton == null){
                    // 某个线程取得了类锁,实例化对象前第二次检查instance是否已经被实例化出来,如果没有,才最终实例出对象
                    if (singleton == null){
                        singleton = new lanhanSingleton();
                    }
                }
            }
            return singleton;
        }
    }
    
  • TestMain

    • public class SingletonMain {
          public static void main(String[] args) {
              lanhanSingleton instance = lanhanSingleton.getInstance();
              instance.setReadings(instance.getReadings()+1);
              read(instance);
              instance.setCollects(instance.getCollects()+1);
              instance.setLikes(instance.getLikes()+1);
              System.out.println("阅读量为:"+instance.getReadings());
              System.out.println("收藏量为:"+instance.getCollects());
              System.out.println("点赞量为:"+instance.getLikes());
          }
          public static void read(lanhanSingleton singleton){
              for (int i=0;i<100;i++){
                  singleton.setReadings(singleton.getReadings()+1);
              }
          }
      }
      
  • 执行结果

    • image-20211101200319853.png
  • 线程安全,调用效率不高,但是能延时加载。

  • 那么饿汉和懒汉在我们实际使用中该如何选择呢?

    • 单例对象 占用资源少,不需要延时加载,枚举 好于 饿汉
    • 单例对象 占用资源多,需要延时加载,静态内部类 好于 懒汉式

路漫漫其修远兮,吾必将上下求索~

如果你认为i博主写的不错!写作不易,请点赞、关注、评论给博主一个鼓励吧~hahah