设计模式之单例模式

设计模式之单例模式
  1. 什么是单例模式

    确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,该类只提供一个取得其对象的方法(静态的)

  2. 单例模式种类

    1. 饿汉式(静态常量)

      1. 实现步骤

        1. 私有化构造方法

        2. 在类内部创建一个静态的常量对象

        3. 向外暴露一个人公共的静态方法返回对象

      2. 优点

        1. 简单,好理解,在类装在的时候就完成实例化,避免的线程同步的问题

      3. 缺点

        1. 在类装在的时候就完成实例化,没有达到懒加载的效果。如果该对象从不使用,会造成内存资源的 浪费

        2. 虽然避免的线程同步问题,不过instance在类装载时就实例化,在单例模式中大多数都是调用getInstance()方法,但是导致类装载的原因有很多种,因此不能确定有其他方式或者其他静态方法导致类装载,这时候初始化就达不到懒加载的效果

    2. 饿汉式(静态代码块):将实例的创建放在一个静态代码块中

      1. 步骤

        1. 私有化构造方法

        2. 定义实例private static Singleton singleton;

        3. 编写静态代码块:初始化实例

        4. 向外暴露一个方公共的类方法返回实例对象

      2. 优缺点和饿汉式(静态常量方式一致

    3. 懒汉式(线程不安全),简单了解就可以

      1. 代码实现

        public class Singleton{
           private static Singleton instance;
           //构造方法私有化
           private Singleton(){}
           //编写向外暴露实例的方法,当调用getInstance()时才创建实例
           public static Singleton getInstance(){
               if(instance == null){
                   instance = new Singleton();
              }
               return instance;
          }
        }

         

      2. 优点

        1. 起到懒加载的效果,但是只能在单线程下面使用

      3. 缺点

        1. 如果在多线程下,一个线程进入的if判断,还未来得及往下执行,另一个线程也通过了这个判断语句,这时候便会产生多个实例。因此在多线程场景下不能使用

      4. 注意:在开发中不推荐使用这种方式

    4. 懒汉式(线程安全,同步方法)

      1. 代码实现

        public class Singleton{
           private static Singleton instance;
           
           //私有化构造方法
           private Singleton(){}
           //加入同步代码块,解决线程不安全问题
           public static synchronized Singleton getInstance(){
               if(instance == null){
                   instance = new Singleton();
              }
               return instance;
          }
        }

         

      2. 优点

        1. 解决了线程安全问题

      3. 缺点

        1. 效率太低,每个线程在想获得实例的时候,执行getInstance()都要进行同步。而其实这个方法只执行一次实例化代码就可以了,后面想要获得该实例,直接进行return就可以了。方法进行同步效率太低

      4. 在开发中,不推荐使用

    5. 懒汉式(线程安全,同步代码块)了解有这回事就行

      1. 代码实现

        public class Singleton{
           private static Singleton instance;
           //私有化构造方法
           private Singleton(){}
           //
           public static Singleton getInstance(){
               if(instance == null){
                   synchronized(Singleton.class){
                       instance = new Singleton();
                  }
              }
               return instance;
          }
        }

         

      2. 优缺点和懒汉式(线程不安全),实际开发中不要使用,存在线程安全问题

    6. 双重检查

      1. 代码实现

        public class Singleton{
           private static volatile ingleton instance;
           
           //私有化构造函数
           private Singleton(){}
           //推荐使用这种单例模式
           public static Singleton getInstance(){
               if(instance == null){
                   synchronized(Singleton.class){
                       if(instance == null){
                          instance = new Singleton();
                      }
                  }  
              }
               return instance;
          }
        }
      2. 
        

         volatile关键字的作用:

        1. 保证了可见性:可见性:是指在线程之间可见,一个线程修改了共享变量的结果,另一个线程马上就能看到
        2. 禁止指令重排序,建立了内存屏障
        3. 不能保证原子性
      3. 优点

        1. 在实战开发中经常使用到的。

        2. 保证了线程安全

        3. 实现了懒加载,不会在成内存资源的浪费

        4. 在一定程度上保证了效率

    7. 静态内部类(推荐使用)

      1. 代码实现

        public class Singleton{
           //了解静态内部类及其特点?装载时机
           private Singleton(){}
           private static class SingletonInstance{
               private static final Singleton INSTANCE = new Singleton();
          }
           private static Singleton getInstance(){
               return SingletonInstance.INSTANCE;
          }
        }

         

      2. 优点

        1. 这种方式采用了类装载机制来保证初始化实例时只有一个线程

        2. 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化的时候,调用getInstance方法,才会装载静态内部类,从而完成Singleton的实例化

        3. 类的静态属性只会在第一次加载类的时候初始化,因此,JVM保证了线程的安全性,在类进行初始化时,别的线程是无法进入的

        4. 避免了线程不安全,利用静态内部类的特点实现延迟加载,效率高

    8. 枚举(推荐使用)

      1. 代码实现

        public class SingletonTest{
           public static void main(String[] args){
               Singleton instance = Singleton.INSTANCE;
               Singleton instance1= Singleton.INSTANCE;
               System.out.println(instance == instance1)//如果为true就是单例的
               
          }
        }
        //m枚举
        enum Singleton{
           INSTANCE;
           public void method(){
               
          }
        }

         

      2. 优点

        1. 避免多线程同步问题

        2. 防止反序列化重新创建的对象

  3. 实例

    1. Hibernate的sessionFactory,它充当数据存储源的代理,并负责创建Session对象。SessionFactory并不是一个轻量级的,一般情况下,一个项目通常只需要一个Sessionfactory就可以了,因此就会使用到单例模式

    2. 在JDK中,java.alng.Runtime就是经典的单例模式(看源码)使用了饿汉式

  4. 单例模式注意事项和细节

    1. 单例模式保证了系统内存中只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能

    2. 在想实例化一个对象的时候必须要记住使用相应获取该对象的方法,而不是使用new的方式

  5. 单例模式的使用场景

    1. 需要频繁的进行创建和销毁的对象,创建对象时耗时过多或消耗资源过多(即重量级对象),但又经常使用到的对象,工具类对象,频繁访问数据库或者文件的对象(比如数据源、session工厂等)

    2. 要求生成唯一序列号的环境

posted @ 2021-06-17 22:11  IT特工  阅读(33)  评论(0编辑  收藏  举报