zoukankan      html  css  js  c++  java
  • 单例模式

    单例模式

    一. 意图

          对于某些类来说,我们其实只需要有一个实例化的对象。比如:注册表,资源管理器,打印机驱动程序等等。

    如果我们保证以上的类只有一个实例,并只提供一个统一的访问点的话。系统中便可以统一管理这个对象。

    以上类只有一个实例,同时也可以节约系统资源,保证对象信息的一致性。

        我们可以通过单例模式来确保对象的唯一性。

    二. 定义

          确保某一个类只有一个实例,只提供一个全局访问点,该类自行实例化并向整个系统提供这个实例,这个类就是单例类

        类图:

       

    三. 单例模式实现的三个要点

    1. 要保证类只有一个实例,就要禁止类的外部直接使用new来创建对象。把单例类的构造函数的可见性要改为private,只在类的内部使用工厂方法创建实例。
    2. 在单例类中定义一个私有的静态的自己类型的成员变量。
    3. 在单例类中定义一个公开的静态的实例化方法。在实例化方法中判断成员变量 是否实例化。如果没有实例化,则创建一个自身实例。如果已经创建,就直接返回成员变量。

             代码示例(java)

            

    四 饿汉式单例与懒汉式单例

         上述的代码示例,在运行多线程的程序中,可能还是存在一些问题,不能保证对象的唯一性。

    例如:有线程1和线程2,同时调用Singleton类的Instance方法。线程1中判断_instance字段为null,对_instance字段进行初始化操作。

         如果Singleton类的初始化信息量大,初始化时间较长。在线程1初始化_instance字段的过程中,假设线程2也调用了Singleton类的Instance方法。如果此时_instance字段还是为null的话,线程2也会对_instance字段进行初始化操作。从而产生了两个Singleton类的实例。Singleton类的实例唯一性无法保证。

         对于多线程的问题,我可以使用饿汉和懒汉单例模式来保证对象的唯一性

    解决方案:

         1.饿汉式单例

    • 类图

      

    • 代码示例(java)

    • 说明

          当Singleton类加载时,静态变量_instance会被初始化,此时Singleton类的私有构造函数会被调用,单例类的唯一实例就被创建了。

         这样在任何线程调用getInstance()方法之前,Singleton类已经被创建,确保了线程安全。

         2.懒汉式单例

    • 类图

         

    • 代码示例(java)

        

    • 说明
      • 懒汉式单例只有在调用了Instance()方法后,才会实例化对象。并不是类一加载的时候,就实例化单例对象。使用延迟加载技术。
      • 在定义静态变量_instance的时,使用了修饰符volatilevolatile修饰符可确保成员变量_instance在多个线程之间信息同步。但是会降低系统运行的效率。
      • 使用关键字synchronized可以对代码进行了锁定,一个线程在实例化对象的时候,另一个线程就必须等待。可以防止多个线程同时实例化Singleton对象。保证了线程的安全,但是锁定代码降低了系统运行的效率。
      • 使用了双重检查锁定,代码示例对_instance是否为null值,进行了两次判断

           第一个_instance == null的判断,是有性能上的好处的。因为只有在第一次_instance == null的时候,才会有对代码进行锁定的操作。_instance不为null的时候,就直接返回了_instance对象了。这样对代码进行锁定的操作只会进行一次了。

           如果不进行双重判断,还是可能将会产生多个单例对象,从而违背单例模式的设计思想。

           假设有线程A和线程B同时调用了Instance()方法,此时_instance为null,线程A和线程B都能通过instance == null的第一次判断。

           由于实现了synchronized加锁机制,线程A和线程B不能同时执行synchronized锁定的代码。

           假设线程A先进入synchronized锁定的代码,实例化Singleton对象。而线程B则处于排队等待状态,它必须等待线程A执行完毕后,才可以进入synchronized锁定的代码中。

           但当线程A实例化完毕后,此时线程B并不知道Singleton对象已经被线程A实例化完毕了。所以必须在synchronized锁定的代码中加上第二个_instance==null的判断。不然线程B将继续创建新的实例,从而导致产生两个单例对象。

       3.饿汉式单例 vs 懒汉式单例

       饿汉式单例

       优点:

           饿汉式单例在类加载的时候就被实例化,无需考虑多线程的问题。代码也不需要锁定,性能上有一定的优势。

       缺点:

           不管系统中是否要引用实例,饿汉式单例在类加载的时候都会创建对象。如果此时系统不需要引用该实例,这样就会造成系统资源的浪费。 

       懒汉式单例

       优点:

           懒汉式单例实现了延迟加载,在类需要被使用时,才会被实例化,不会一直占用系统资源。

       缺点:

           要处理好多线程同时访问的问题,就需要锁定代码,考虑多个线程的同步,这样就会对系统的性能造成一定的影响。

    五.总结

        单例模式是一种比较简单的创建型模式,在某种程度上来说它是限制了而不是促进了类的创建。保证类只有一个实例,并只提供一个全局的访问点。在很多应用软件中都有广泛的应用。

  • 相关阅读:
    Android混淆
    Web开发人员应当知道的15个开源项目
    应用开发10种免费推广的方法
    (转载)Comparing C++ and C (Inheritance and Virtual Functions)
    JCTVC 会议输出文档
    HEVC bit depth increasment
    函数指针声明时的形参列表可以没有
    关于链接 Linkage
    二级指针和二维数组
    C 与 C++互相调用函数,变量
  • 原文地址:https://www.cnblogs.com/YaoxTao/p/4931895.html
Copyright © 2011-2022 走看看