什么是单例模式
保证一个类仅有一个实例,提供一个访问它的全局访问点。
要点:
- 单例类只能有一个实例
- 它必须自行创建实例
- 他必须自行向系统提供这个实例
具体实现:
- 只提供私有的构造函数
- 类定义中含有一个该类的静态成员对象
- 提供了静态的公有方法用于创建或获取它本身的静态私有对象。
分类:
- 懒汉模式:第一次使用时才创建唯一的实例,实现了延迟加载。
- 饿汉模式:程序启动就创建唯一的实例,即单例类定义的时候就进行实例化。
饿汉单例模式
-
私有化构造函数
-
类定义时创建实例
-
私有的静态类指针指向实例(类外声明)
-
公有的静态方法访问唯一的实例
-
定义静态的嵌套类对象的析构函数去析构单例对象,待程序结束销毁实例。
class CSingleTon { public: static CSingleTon* GetSingleTon() { return msin; } class CSingleDes { public: ~CSingleDes() { if(CSingleTon::msin!=NULL) { delete CSingleTon::msin; msin=NULL; cout<<"~CSingleDes() here"<<endl; } } }; static CSingleDes mdes; private: static CSingleTon* msin; CSingleTon() { cout<<"CSingleTon() here"<<endl; } CSingleTon(const CSingleTon& rhs) {} }; CSingleTon* CSingleTon::msin=new CSingleTon(); CSingleTon::CSingleDes mdes; int main() { cout << "Process Begin" << endl; CSingleTon *s1 = CSingleTon::GetSingleTon(); CSingleTon *s2 = CSingleTon::GetSingleTon(); cout << "s1 = " << s1 << endl << "s2 = "<< s2 << endl; //delete s1; }
在类被加载的时候创建实例,是线程安全的。
懒汉单例模式
class CSingleTon
{
public:
static CSingleTon* GetSingleTon()
{
if(msin==NULL)
{
msin=new CSingleTon();
}
return msin;
}
class CSingleDes
{
public:
~CSingleDes()
{
if(CSingleTon::msin!=NULL)
{
delete CSingleTon::msin;
msin=NULL;
cout<<"~CSingleDes() here"<<endl;
}
}
};
static CSingleDes mdes;
private:
static CSingleTon* msin;
CSingleTon()
{
cout<<"CSingleTon() here"<<endl;
}
};
CSingleTon* CSingleTon::msin=NULL;
CSingleTon::CSingleDes mdes;
懒汉单例模式线程安全版本
经典枷锁版本
class CSingleTon
{
public:
static CSingleTon* GetSingleTon()
{
pthread_mutex_lock(&mutex);//加锁
if(msin==NULL)
{
msin=new CSingleTon();
}
pthread_mutex_unlock(&mutex);//解锁
return msin;
}
class CSingleDes
{
public:
~CSingleDes()
{
if(CSingleTon::msin!=NULL)
{
delete CSingleTon::msin;
msin=NULL;
cout<<"~CSingleDes() here"<<endl;
}
}
};
static CSingleDes mdes;
private:
static pthread_mutex_t mutex;
static CSingleTon* msin;
CSingleTon()
{
cout<<"CSingleTon() here"<<endl;
}
};
CSingleTon* CSingleTon::msin=NULL;
CSingleTon::CSingleDes mdes;
pthread_mutex_t CSingleton::mutex = PTHREAD_MUTEX_INITIALIZER;
优化版本:双重检查锁机制
class CSingleTon
{
public:
static CSingleTon* GetSingleTon()
{
if(msin==NULL)
{
pthread_mutex_lock(&mutex);//加锁
if(msin==NULL)
{
msin=new CSingleTon();
}
pthread_mutex_unlock(&mutex);//解锁
}
return msin;
}
class CSingleDes
{
public:
~CSingleDes()
{
if(CSingleTon::msin!=NULL)
{
delete CSingleTon::msin;
msin=NULL;
cout<<"~CSingleDes() here"<<endl;
}
}
};
static CSingleDes mdes;
private:
static pthread_mutex_t mutex;
static CSingleTon* msin;
CSingleTon()
{
cout<<"CSingleTon() here"<<endl;
}
};
CSingleTon* CSingleTon::msin=NULL;
CSingleTon::CSingleDes mdes;
pthread_mutex_t CSingleton::mutex = PTHREAD_MUTEX_INITIALIZER;
使用内部静态变量保证线程安全
函数内部的静态局部变量的初始化是在函数第一次调用时执行; 在之后的调用中不会对其初始化。 在多线程环境下,仍能够保证静态局部变量被安全地初始化,并只初始化一次。
class CSingleTon
{
public:
static CSingleTon* GetSingleTon()
{
static CSingleTon msin;
return &msin;
}
~CSingleDes()
{
cout<<"~CSingleDes() here"<<endl;
}
private:
CSingleTon()
{
cout<<"CSingleTon() here"<<endl;
}
};
g++在变量初始化的前后,自动加了锁保护代码。
单例模式的使用场景
- 系统只需要一个实例对象,或者考虑到资源消耗的太大而只允许创建一个对象。
- 客户调用类的单个实例只允许使用一个公共访问点,除了该访问点之外不允许通过其它方式访问该实例 (就是共有的静态方法)。