设计模式(一)单例模式

1.单例模式(Singleton):由于某种需要,要保证一个类在程序的生命周期中只有一个实例,并提供一个该实例的全局访问方法。

2.单例模式(Singleton)结构图:

Singleton类,定义了一个GetInstance操作,允许客户访问他的唯一实例,

                      GetInstance是一个静态方法,主要负责创建自己的唯一实例

3.特点:

   (1)一个类只能有一个实例

    (2)该类可以自行创建这个实例

    (3)该类能向整个系统返回这个实例

4.单例模式一般包含三个要素:

   (1)私有的静态的实例对象  private static instance

    (2)私有的构造函数 (保证在该类外部无法通过new方法创建实例对象) private Singleton(){}

    (3)公有的静态的访问该实例的方法  public static Singleton GetInstance(){} 

5.单例模式的实现

    (1)懒汉式(在使用时才实例化)

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()//最好返回引用,防止用户不小心删除指针  
 5     {  
 6         if(instance == NULL)  
 7             instance = new Singleton();  
 8         return *instance;  
 9     }  
10 private:  
11     Singleton(){}  
12     ~Singleton();  
13     Singleton(const Singleton&);  
14     Singleton &operator = (const Singleton&);//赋值和拷贝构造要声明为私有  
15     static Singleton *instance;  
16 };  
17 Singleton* Singleton::instance=NULL;//静态的数据成员必须要在类外初始化  

  这种实现方法没有考虑多线程安全的情况,在多线程的程序中,如果有多个线程同时访问Singleton类,调用GetInstance()方法,就有可能创建出多个实例。

   

(2)基于懒加载的线程安全(一)使用互斥锁

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()  
 5     {  
 6         Lock();  
 7         if(instance == NULL)  
 8         {  
 9             instance = new Singleton();  
10         }  
11         Unlock();  
12         return *instance;  
13     }  
14 private:  
15     Singleton(){}  
16     ~Singleton();  
17     Singleton(const Singleton&);  
18     Singleton &operator = (const Singleton&);  
19     static Singleton *instance;  
20 };  
21 Singleton* Singleton::instance=NULL;  

 Lock是用来确保当一个线程位于代码的临界区时,另一个线程不能进入临界区。这样就确保了在多线程环境下,有多个线程同时访问时只有一个线程可以进入加锁的部分,保证只创建一个实例。但是加锁这个动作会不停地在用户态和内核态之间切换,极端情况如只有单线程,这个加锁的动作会严重的拖慢效率。

  (3)基于懒加载的线程安全(二)

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()  
 5     {  
 6         if(instance == NULL)  
 7         {  
 8             Lock();  
 9             if(instance == NULL)  
10             {  
11                 instance = new Singleton();  
12             }  
13             Unlock();             
14         }  
15         return *instance;  
16     }  
17 private:  
18     Singleton(){}  
19     ~Singleton();  
20     Singleton(const Singleton&);  
21     Singleton &operator = (const Singleton&);  
22     static Singleton *instance;  
23 };  
24 Singleton* Singleton::instance=NULL;  

  为了解决上一版本每次调用GetInstance方法是都要lock的问题,这次使用了双重if判断条件,先判断实例是否存在,如果不存在,再进行加锁。

(4)饥汉式

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()  
 5     {  
 6         return instance;  
 7     }  
 8 private:  
 9     Singleton(){}  
10     ~Singleton();  
11     Singleton(const Singleton&);  
12     Singleton &operator = (const Singleton&);  
13     static Singleton instance;  
14 };  
15 Singleton Singleton::instance;  

在饥汉模式下,单例类在定义时就创建了对象,对类进行了初始化,之后再有线程调用GetInstance()函数时,都返回的是同一个对象的指针,所以饥汉式是线程安全的。

但是函数外的static对象在不同编译单元中的初始化顺序是未定义的,两个单例交互就可能出现问题。

 

原文地址:https://www.cnblogs.com/lulu1997/p/8491963.html