如何实现一个类只能实例化一个对象?
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例
显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
从具体实现角度来说,就是以下三点:一是单例模式的类只提供私有的构造函数,二是类定义中含有一个该类的静态私有对象,三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。
版本一:使用快加载,不论是否使用直接实例化
class Singleton
{
public:
static Singleton& getInstance()
{
return single;
}
private:
Singleton() {};
static Singleton single;
};
Singleton Singleton::single = Singleton::getInstace() ;
版本二:使用懒加载,只有在使用时才实例化
class Singleton
{
public:
static Singleton * getIntance()
{
if(single == NULL)
{
single = new Singleton();
}
return single;
}
private:
Singleton(){}
static Singleton *single;
};
Singleton * Singleton::single = NULL;
版本三:考虑多线程安全问题,使用互斥锁同步
判断是否是线程安全的——是否存在竟态条件(存在竟态条件,非线程安全的)
判断是否存在竟态条件——随着线程调度顺序不同,程序结果是否相同(不相同,存在竟态条件)
存在竟态条件的代码区称为临界区、临界区的代码必须是原子操作、实现原子操作要使用互斥锁
在本代码中,if语句不是原子操作,需要使用互斥锁同步
class Singleton
{
public:
static Singleton* getIntance()
{
pthread_mutex_lock(&mutex);
if (pobject == NULL)
{
single= new Singleton();
}
pthread_mutex_unlock(&mutex);
return single;
}
private:
Singleton(){}
static Singleton *single;
};
Singleton* Singleton::single= NULL;
版本四:版本三虽然解决了多线程安全问题,但在单线程中每次都需要获取锁释放锁而导致效率低下,所以将锁放到if语句中
class Singleton
{
public:
static Singleton* getIntance()
{
if (pobject == NULL)
{
pthread_mutex_lock(&mutex);
single= new Singleton();
pthread_mutex_unlock(&mutex);
}
return single;
}
private:
Singleton(){}
static Singleton *single;
};
Singleton* Singleton::single= NULL;
版本五:版本四虽然解决了单线程效率问题,但由于new不是原子操作,依然存在多线程安全问题,使用双重if判断
单线程时,只需要执行一次获取释放互斥锁操作,之后第一个if语句都为false
多线程时,依旧考虑线程安全与竞态条件问题
class Singleton
{
public:
static Singleton * getIntance()
{
if(single == NULL)
{
pthread_mutex_lock(&mutex);//多线程线程安全问题
if(single == NULL)//单线程时效率问题
{
single = new Singleton();
}
pthread_mutex_unlock(&mutex);
}
return single;
}
private:
Singleton(){}
static Singleton *single;
};
Singleton * Singleton::single = NULL;
版本六:考虑编译器的指令优化和CPU的动态指令优化
volatile关键字阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回内存
volatile关键字阻止编译器调整操作volatile变量的指令操作
barrier指令会阻止CPU对指令进行动态换序优化
class Singleton
{
public:
volatile static Singleton* getIntance()
{
if (single== NULL)
{
pthread_mutex_lock(&mutex);//多线程线程安全问题
if (single== NULL)//单线程时的效率问题
{
Singleton* temp = new Singleton;
barrier();//防止CPU对指令进行动态换序优,使对象的构造一定在barrier完成,因此赋值给pobject的对象是完好的
single= temp;
}
pthread_mutex_lock(&mutex);
}
return single;
}
private:
Singleton(){}
volatile static Singleton *single;
};
volatile Singleton* Singleton::single= NULL;//快加载 懒加载