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;
  这样的双重检测机制,提高了单例模式在多线程下的效率,因为这样的代码,只需要在第一次创建实例的时候,需要加锁,其他的时候,线程无需排队等待加锁之后,再去判断了,比较高效。