1 //考虑到多线程情形下的单例模式 2 class Singleton 3 { 4 public: 5 //get 方法 6 static Singleton * getInstance(){ 7 //联系互斥信号量机制,给代码加锁 8 lock(); 9 //判断 null 10 if (NULL == instance) { 11 //判断类没有生成对象,才实例化对象,否则不再实例化 12 instance = new Singleton(); 13 } 14 //使用完毕,解锁 15 unlock(); 16 //返回一个实例化的对象 17 return instance; 18 } 19 private: 20 //声明对象计数器 21 int count = 0; 22 //声明一个静态的实例 23 static Singleton *instance; 24 //私有构造函数 25 Singleton(){ 26 count++; 27 cout << "实例化了" << count << "个对象!" << endl; 28 } 29 }; 30 //初始化 instance 31 Singleton * Singleton::instance = NULL; |
此时,还是有 ab 两个线程来运行这个单例类,由于在同一时刻,只有一个线程能拿到同步锁(互斥信号量机制),a 拿到了同步锁,b 只能等待,如果 a发现实例还没创建,a 就会创建一个实例,创建完毕,a 释放同步锁,然后 b 才能拿到同步锁,继续运行接下来的代码,b 发现 a 线程运行的时候,已经生成了一个实例,b 线程就不会重复创建实例了,这样就保证了我们在多线程环境中只能得到一个实例。
继续分析多线程下的懒汉式单例模式
代码中,每次 get 方法中,得到 instance,都要判断是否为空,且判断是否为空之前,都要先加同步锁,如果线程很多的时候,就要先等待加了同步锁的线程运行完毕,才能继续判断余下的线程,这样就会造成大量线程的阻塞,且加锁是个非常消耗时间的过程,应该尽量避免(除非很有必要的时候)。可行的办法是,双重判断方法。
因为,只是在实例还没有创建的时候,需要加锁判断,保证每次只有一个线程创建实例,而当实例已经创建之后,其实就不需要加锁操作了。
双重判断的线程安全的懒汉式单例模式
1 class Singleton 2 { 3 public: 4 //get 方法 5 static Singleton * getInstance(){ 6 //先判断一次 null,只有 null 的时候需要加锁,其他的时候,其实不需要加锁 7 if (NULL == instance) { 8 //联系互斥信号量机制,给代码加锁 9 lock(); 10 //然后再次判断 null 11 if (NULL == instance) { 12 //判断类没有生成对象,才实例化对象,否则不再实例化 13 instance = new Singleton(); 14 } 15 //使用完毕,解锁 16 unlock(); 17 } 18 //返回一个实例化的对象 19 return instance; 20 } 21 private: 22 //声明对象计数器 23 int count = 0; 24 //声明一个静态的实例 25 static Singleton *instance; 26 //私有构造函数 27 Singleton(){ 28 count++; 29 cout << "实例化了" << count << "个对象!" << endl; 30 } 31 }; 32 //初始化 instance 33 Singleton * Singleton::instance = NULL; |
这样的双重检测机制,提高了单例模式在多线程下的效率,因为这样的代码,只需要在第一次创建实例的时候,需要加锁,其他的时候,线程无需排队等待加锁之后,再去判断了,比较高效。