上篇我们讲了工厂模式,这章我们来聊聊单例模式,单例模式也是最常用的模式之一
在这篇里我要讲到懒汉式单例(经典单例)和饿汉式单例,以及经典单例的修改等。
经典单例:
以下代码在VS2012上编译通过
.h文件
class singleton
{
private:
singleton();
static singleton* mInstance;
public:
static singleton* getInstance();
};
.cpp文件
singleton::singleton()
{
}
singleton* singleton::getInstance()
{
if(mInstance==NULL)
{
mInstance=new singleton();
}
return mInstance;
}
singleton* singleton::mInstance=NULL;
调用文件:
int _tmain(int argc, _TCHAR* argv[])
{
singleton* instance= singleton::getInstance();
singleton* instance2= singleton::getInstance();
if(instance==instance2)
{
cout<<"The same"<<endl;
}
return 0;
}
执行结果:
The same
问题:以上的单例模式如果在多线程中会怎么样呢?
我们可以想想这种情况,如果线程1在进入了if(mInstance==NULL) 这个判断区域内的时候,要去实例化类,这个过程中要对新的实例各种初始化完之后才将新的实例的内存地址赋值给mInstance,也就是说这段时间内,mInstance也是等于NULL的,如果这个时候线程2再来实例化一次,还是能进入if(mInstance==NULL) 这个判断区域内的。所以最终我们就得到了两个不一样的实例,这显然是有悖于单例模式初衷的。
解答:方法一,任何一个线程可以在进入if(mInstance==NULL)之前加锁,然后出来后解锁。 方法二,饿汉单例模式
饿汉单例模式:
为什么称为饿汉单例模式呢?本质上就是刚创建这个类的时候就实例化这个类了,而不是要用到的时候再去实例化,既然使用过程中没有创建新的实例,自然就不可能有两个实例了。
h文件
class singleton
{
private:
singleton();
static singleton* mInstance;
public:
static singleton* getInstance();
};
.cpp文件
singleton::singleton()
{
}
singleton* singleton::getInstance()
{
return mInstance;
}
singleton* singleton::mInstance=new singleton();
由以上可以看出饿汉单例模式,每次getInstance()的调用过程中,完全没有实例化的操作,从根本上杜绝了两个实例的现象。虽然一开始就要占一点内存,不过在多线程中利比弊大多了,好了今天就写到这里了,肚子饿了。。。饿汉+1