单例模式:就是一个类只产生一个对象。
实现单例模式: 要产生一个对象,就要把构造函数定义为私有的。
要定义一个该类的静态私有对象。
要对外提供一个函数,自行创建这个私有对象,当然,这个函数要定义为静态成员函数。
单例模式的快加载:
1.
class SingleTon
{
public:
static SingleTon* getInstance() //单例模式快加载
{
return &singleTon;
}
private:
SingleTon() {}
static SingleTon singleTon; //存放于数据段,程序运行起来就已经初始化了,只初始化一次。
};
SingleTon SingleTon::singleTon;
2.
class SingleTon
{
public:
static SingleTon* getInstance() //单例模式快加载
{
static SingleTon singleTon;
return &singleTon;
}
private:
SingleTon() {}
};
static局部变量只初始化一次,调用函数getInstance()时才初始化。
单例模式的懒加载:
class SingleTon
{
public:
static SingleTon* getInstance() //单例模式懒加载,只有在使用的时候才生成
{
if(singleTon == NULL)
{
singleTon = new SingleTon();
}
return singleTon;
}
private:
SingleTon() {}
static SingleTon* singleTon;
};
SingleTon* SingleTon::singleTon = NULL;
考虑多线程安全,要使用互斥锁。
怎样判断是不是线程安全的?判断是否存在竞态条件
判断竞态条件:随着每次调度顺序的不同,执行结果也不一样
发生竞态条件的代码段称作临界区,临界区代码段需要保证原子性操作,要保证原子性操作,对临界区代码进行互斥,使用互斥锁。
多线程安全的单例模式(懒加载):
class SingleTon
{
public:
static SingleTon* getInstance()
{
pthread_mutex_init(&mutex);
if(singleTon == NULL)
{
pthread_mutex_lock(&mutex);
if(singleTon == NULL)
{
singleTon = new SingleTon();
}
pthread_mutex_unlock(&mutex);
}
return singleTon;
}
private:
SingleTon() {}
volatile static SingleTon* singleTon;
};
SingleTon* SingleTon::singleTon = NULL;
使用双重if判断,解决了多线程安全问题。
使用volatile关键字是为了保证不同线程对SingleTon进行操作时的可见性和阻止编译器调整变量的指令操作。