/*
代码中经常会使用到单例模式,单例模式就是隐藏构造函数,提供获取一个实例的静态方法。
但是在多线程场景下,单例模式会有一些不同。例如Config类的instance方法如下
*/
//获取一个实例(对外接口)
static Config * instance()
{
if (NULL == m_instance)
{
//加锁(多线程场景下)
m_mutex.acquire();
if (NULL == m_instance)
{
m_instance = new Config();
/*
类似于这个类的初始化,我是不建议放在这里的,
因为如果init方法执行失败,但是实例仍然不为NULL,
建议在main函数中第一次调用instance方法时,执行init方法初始化实例
(注意init方法也是只能执行一次的,请考虑多线程场景)
init方法放在这个纯粹是为了解释这个场景下单例的使用
*/
m_instance->init();
}
//解锁
m_mutex.release();
}
return m_instance;
}
/*
如果在instance方法中不加锁,在多线程的场景下,有可能创建出多个实例。
instance方法在加锁之后,还是有问题的。
假设线程A正在执行m_instance->init()方法(init方法执行的时间很长),此时线程B开始执行instance方法,
发现m_instance != NULL(因为线程A已经构造了该实例),那么线程B就会直接获取到这个并没有执行完init方法的m_instance实例,
线程B用这个m_instance去执行操作,就会出现问题。
*/
/*
简单的改进就是,去掉前边的判断,直接加锁,这样就避免了该问题,
线程B进行进来的时候因为线程A已经获取到锁,线程B会等待,
等到线程A释放锁之后(所有初始化操作已经完成),线程B判断m_instance != NULL,
线程B可以使用m_instance这个实例了
*/
static Config * Config::instance()
{
//加锁(多线程场景下)
m_mutex.acquire();
if (NULL == m_instance)
{
m_instance = new Config();
m_instance->init();
}
//解锁
m_mutex.release();
return m_instance;
}
/*
但是这样的改进会出现一个新问题,就是每次调用这个单例就会加锁判断,频繁调用会影响速度
*/
/*
再次改进方案,使用一个临时变量构造,初始化,成功后再赋值给m_instance
这样避免了多线程操作影响,又不影响速度
*/
static Config * instance()
{
if (NULL == m_instance)
{
//加锁(多线程场景下)
m_mutex.acquire();
if (NULL == m_instance)
{
Config * pInstance = new Config();
pInstance->init();
m_instance = pInstance;
}
//解锁
m_mutex.release();
}
return m_instance;
}