第一个设计模式——单例模式

目录

一、特点:

二、实现单例模式步骤

三、饿汉式

四、懒汉式

五、双重检查锁

六、静态内部类

七、枚举

八、可能被反序列化和反射破坏什么意思?

九、如何解决呢?


一、特点:

  1. 唯一性,单例模式确保程序中只有一个实例存在
  2. 节省内存开销,不用多次创建对象

二、实现单例模式步骤

  1. 私有化构造函数,防止外部实例化
  2. 提供公共获取单例对象的静态方法

三、饿汉式

饿汉式是什么?

指在类加载时就完成了初始化。

  • java实现

    public class Singleton {
    //创建一个静态的单例对象
    private static final Singleton instance = new Singleton();

      //私有化构造函数,防止外部实例化
      private Singleton(){}
    
      //提供公共的获取单例对象的静态方法
      public static Singleton getInstance(){
          return instance;
      }
    

    }

  • kotlin实现

    object Singleton {
    //Kotlin的object关键字自动实现了饿汉式单例
    }

优点:是线程安全的,因为JVM在进行类加载的时候,会进行加锁,每个类只有一份class对象,然后类加载的时候就会执行静态代码块、静态变量。

缺点:可能被反序列化和反射破坏、浪费资源,当你不需要单例实例,只想调用类中的静态方法时,它都会帮你执行静态代码块和静态变量,因为类加载。例如:


四、懒汉式

懒汉式是什么?

是指第一次调用时才初始化

1.不正确的懒汉式单例模式:

虽然最后打印的结果是一样的对象,这是只有主线程的情况,但是如果在多线程下呢?

java例子:

koltin例子:

可以看到如果在多线程下,该对象就会被创建多次,所以这种方法是不对的。

2.正确的懒汉式单例模式:

  • java实现

    public class Singleton {
    //创建一个静态的单例对象
    private static Singleton instance = null;

      //私有化构造函数,防止外部实例化
      private Singleton(){
          System.out.println("Singleton正在实例化");
      }
    
      //提供公共的获取单例对象的静态方法
      public synchronized static Singleton getInstance(){
          if(instance == null){
              instance = new Singleton();
          }
          return instance;
      }
    

    }

  • kotlin 实现

    class Singleton {
    private constructor(){
    println("Singleton正在被实例")
    }

      companion object{
          private var instance:Singleton? = null
    
          @Synchronized
          public fun  getInstance():Singleton{
              if(instance == null){
                  instance = Singleton()
              }
              return instance!!
          }
      }
    

    }

优点:在多线程下,能保证该类只实例一次。

缺点:可能被反序列化和反射破坏、为方法加锁,粒度太大,即锁定的范围过宽。这意味着锁保护的区域较大,包括了多个操作或整个方法,这会对系统的性能和并发能力产生一些负面影响,多个线程可能因为需要访问一个被锁定的方法而排队等待,导致线程资源的低效使用。

进行优化,减小锁的范围:


五、双重检查锁

  • java实现

    public class Singleton {
    //创建一个静态的单例对象
    private volatile static Singleton instance = null;

      //私有化构造函数,防止外部实例化
      private Singleton(){
          System.out.println("Singleton正在实例化");
      }
    
      //提供公共的获取单例对象的静态方法
      public  static Singleton getInstance(){
          if(instance == null){
              synchronized(Singleton.class) {
                  if(instance == null) {
                      instance = new Singleton();
                  }
              }
          }
          return instance;
      }
    

    }

  • kotlin实现

    class Singleton {
    private constructor(){
    println("Singleton正在被实例")
    }

      companion object{
          @Volatile
          private  var instance:Singleton? = null
    
    
          public fun  getInstance():Singleton{
              if(instance == null){
                  synchronized(Singleton::class.java) {
                      if(instance == null) {
                          instance = Singleton()
                      }
                  }
              }
              return instance!!
          }
      }
    

    }

优点:线程安全、提高了性能、避免了资源浪费。

缺点:可能被反序列化和反射破坏、结构复杂,要记得加volatile关键字。


六、静态内部类

  • java实现

    public class Singleton {

      //私有化构造函数,防止外部实例化
      private Singleton(){
          System.out.println("Singleton正在实例化");
      }
    
      // 静态内部类,只有在第一次被访问时才会被加载
      private static class SingletonHolder {
          private static final Singleton INSTANCE = new Singleton();
      }
    
      public static Singleton getInstance() {
          return SingletonHolder.INSTANCE;
      }
    

    }

  • kotlin实现

    class Singleton {
    private constructor(){
    println("Singleton正在被实例")
    }

      companion object{
          object SingletonHolder{
              val INSTANCE = Singleton()
          }
          
          public fun getInstance():Singleton{
              return SingletonHolder.INSTANCE
          }
      }
    

    }

优点:线程安全、避免了资源浪费、实现简单

缺点:可能被反序列化和反射破坏、它的线程安全是依靠类加载,但是类加载是耗性能的,类加载的过程:


七、枚举

  • java实现

    public enum Singleton {
    INSTANCE;

      // 可以在这里添加其他方法和属性
    

    }

  • kotlin实现

    enum class Singleton {
    INSTANCE;

      // 可以在这里添加其他方法和属性
    

    }

优点:代码写法简洁优雅、线程安全(通过反编译class文件,可以看到INSTANCE是一个静态变量。那么就是通过类加载来保证线程安全的)、可以防止反序列化和反射破坏单例、并且不用手动私有化构造函数。

缺点:不能继承其它类,因为它内部已经继承了Enum类、它的线程安全是依靠类加载,但是类加载是耗性能的。


八、可能被反序列化和反射破坏什么意思?

1.反序列化破坏:将一个单例对象进行序列化后,再反序列化,而反序列化的对象和程序对象不是同一个对象。除了枚举的单例,其它的方式都会被反序列化破坏。

例如,以饿汉式为例子:

2.反射破坏:通过反射调用类的无参构造函数进行创建出来对象和程序的单例对象不是同一个对象。除了枚举的单例,其它的方式都会被反射破坏

例如,以饿汉式为例子:

3.看看枚举的例子:

反射创建对象,直接报错:

序列化和反序列化不会破坏对象:


九、如何解决呢?

  • 对于序列化破坏:

  • 对于反射破坏:

相关推荐
一 乐1 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
数云界1 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
阑梦清川1 小时前
Java继承、final/protected说明、super/this辨析
java·开发语言
快乐就好ya3 小时前
Java多线程
java·开发语言
IT学长编程3 小时前
计算机毕业设计 二手图书交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·二手图书交易系统
CS_GaoMing3 小时前
Centos7 JDK 多版本管理与 Maven 构建问题和注意!
java·开发语言·maven·centos7·java多版本
艾伦~耶格尔4 小时前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man20174 小时前
基于spring boot的篮球论坛系统
java·spring boot·后端
2401_858120534 小时前
Spring Boot框架下的大学生就业招聘平台
java·开发语言
S hh4 小时前
【Linux】进程地址空间
java·linux·运维·服务器·学习