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

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


相关文章

设计模式系列:设计模式


前言

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

一、饿汉单例

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    java复制代码//饿汉单例模式
    @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

+ 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
csharp复制代码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](https://gitee.com/songjianzaina/juejin_p13/raw/master/img/ba81f852029ec1b88a8bd7dcd92eb48ec4b028cbbbc3e88bb6f13ad912ed94d3)
  • 一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式。
  • 但是问题也比较明显。单例在还没有使用到的时候,初始化就已经完成了。
  • 也就是说,如果程序从头到位都没用使用这个单例的话,单例的对象还是会创建。这就造成了不必要的资源浪费。所以不推荐这种实现方式。

二、懒汉单例

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    java复制代码//懒汉单例模式
    @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

+ 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
csharp复制代码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](https://gitee.com/songjianzaina/juejin_p13/raw/master/img/ecbbad863e8963e6766b132c09cdf775be8be489cdbf70efc1613261670add49)
  • 线程安全,调用效率不高,但是能延时加载。
  • 那么饿汉和懒汉在我们实际使用中该如何选择呢?
+ 单例对象 占用资源少,不需要延时加载,枚举 好于 饿汉
+ 单例对象 占用资源多,需要延时加载,静态内部类 好于 懒汉式

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

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

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%