• 设计模式之单例模式


    设计模式之单例模式
    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. 要求生成唯一序列号的环境

  • 相关阅读:
    HDU.5765.Bonds(DP 高维前缀和)
    SPOJ.TLE
    LOJ.2585.[APIO2018]新家(二分 线段树 堆)
    BZOJ.2679.Balanced Cow Subsets(meet in the middle)
    BZOJ.3293.[CQOI2011]分金币(思路)
    BZOJ.4558.[JLOI2016]方(计数 容斥)
    BZOJ.3631.[JLOI2014]松鼠的新家(树上差分)
    BZOJ.1568.[JSOI2008]Blue Mary开公司(李超线段树)
    BZOJ.1071.[SCOI2007]组队(思路)
    BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)
  • 原文地址:https://www.cnblogs.com/juddy/p/14897513.html
Copyright © 2020-2023  润新知