• 单例模式


      单例模式(Singleton),是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

      优点: 
          1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例。
          2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。 
          3.提供了对唯一实例的受控访问。 
          4.由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。 省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
          5.避免对共享资源的多重占用。 

          6.有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

      缺点:

       1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。 
          2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。 
          3.单例类的职责过重,在一定程度上违背了“单一职责原则”。 
          4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。 

      下面写一个最基础的单例模式:

     1 public class Singleton1 {
     2 
     3     //初始化一个实例对象
     4     private static Singleton1 sin = new Singleton1();
     5     
     6     /**
     7      * 私有构造器,防止被new出来
     8      */
     9     private Singleton1 (){
    10     }
    11     
    12     /**
    13      * 获取唯一实例的方法
    14      * @return
    15      */
    16     public static Singleton1 getInstance(){
    17         return sin;
    18     }
    19 }

      上面的代码中有一个缺点就是,这个类在加载的时候会直接new一个静态对象出来,当系统中这样的类比较多时,会使得项目启动非常慢。现在流行的设计都讲求“延迟加载”,我们可以在第一次使用的时候才初始化第一个该类对象,所以上面代码只适合在小程序。

      对上面代码进行优化:

     1 public class Singleton2 {
     2     //将此处改为null是为了懒加载
     3     private static Singleton2 sin = null;
     4         
     5     /**
     6      * 私有构造器,防止被new出来
     7      */
     8     private Singleton2 (){
     9     }
    10     
    11     /**
    12      * 第一次使用时初始化
    13      * @return
    14      */
    15     public static Singleton2 getInstance(){
    16         if (sin == null){
    17             sin = new Singleton2();
    18         }
    19         return sin;
    20     }
    21 }

      上面的单例模式基本可以满足程序,但是如果处于多线程环境下肯定会出现问题,所以在上面代码的基础上进行加锁。

     1 public class Singleton3 {
     2     private static Singleton3 sin = null;
     3 
     4     private Singleton3 (){
     5     }
     6     
     7     /**
     8      * 在初始化方法上面进行加锁操作
     9      * @return
    10      */
    11     public static synchronized Singleton3 getInstance(){
    12         if (sin == null){
    13             sin = new Singleton3();
    14         }
    15         return sin;
    16     }
    17 }

      上面代码对初始化方法进行加锁,但是是对整个方法进行了加锁,粒度有点大,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。

     1 public class Singleton4 {
     2     private static Singleton4 sin = null;
     3 
     4     private Singleton4 (){
     5     }
     6     
     7     /**
     8      * 只在new时进行加锁,双重同步锁
     9      * @return
    10      */
    11     public static Singleton4 getInstance(){
    12         if (sin == null){
    13             synchronized (sin){
    14                 if (sin == null){
    15                     sin = new Singleton4();
    16                 }
    17             }
    18         }
    19         return sin;
    20     }
    21 }

      上述代码看似没问题,其实还是会存在一些问题,当A线程执行sin = new Singleton4()时,jvm会先划分一部分空白内存并赋值给sin,然后走出synchronized方法块,然后B线程执行时发现sin已经有引用就直接返回,其实此时sin还没有被实例化。所以就有了下面的方式,既不用加锁,也可以实现懒加载。

     1 public class Singleton5 {
     2     private Singleton5 (){
     3     }
     4     /**
     5      * 使用内部类来维护单例。
     6      * @author Wuyouxin
     7      *
     8      */
     9     private static class SingletonFactory{
    10         private static Singleton5 sin = new Singleton5();
    11     }
    12     
    13     /**
    14      * 当第一次调用时加载上面的内部类,初始化sin
    15      * @return
    16      */
    17     public static Singleton5 getInstance(){
    18         return SingletonFactory.sin;
    19     } 
    20     
    21 }

      上述几种方式都可以实现单例模式,可以在不同的业务场景使用不同的方式去创建单例模式。

  • 相关阅读:
    二叉树的遍历以及创建——by leona
    利用图像压缩模型抵御对抗样本 by ch
    卡尔曼滤波器及其扩展的个人学习笔记~
    用GAN进行图像压缩 by ch
    用深度学习进行图像压缩 by ch
    3D目标检测&6D姿态估计之SSD-6D算法--by leona
    如何搭建三维重建工程体系
    C++面对对象(一)
    Pybind11教程
    C++的debug和release区别
  • 原文地址:https://www.cnblogs.com/wuyx/p/8850026.html
Copyright © 2020-2023  润新知