单例模式(饿汉模式与懒汉模式)

单例模式

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。

饿汉模式

程序一启动对象则会产生。因为是在类中私有化了静态成员对象;只有声明为静态成员,才可在类中定义自身成员对象;它是在进入主函数之前就生成的,所以说程序一启动对象则会生成,也因此,如果这个单例对象在多线程并发环境下频繁使用,性能要求较高 ,则此模式可以避免资源竞争,提高响应速度更好。
优点:简单;
缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不一定

class Singleton
 {
 public:
 static Singleton* GetInstance()
 {
 return &m_instance;
 }
 
 private:
 // 构造函数私有
 Singleton(){};
 
 // C++98 防拷贝
 Singleton(Singleton const&); 
 Singleton& operator=(Singleton const&); 
 
 // or
 
 // C++11
 Singleton(Singleton const&) = delete; 
 Singleton& operator=(Singleton const&) = delete; 
 
 static Singleton m_instance;//只有声明为静态成员,才可在类中定义自身成员对象;它是在进入主函数之前就生成的。
 };
 
 Singleton Singleton::m_instance; // 在程序入口之前就完成单例对象的初始化

懒汉模式

优点:懒汉模式是使用时调用即可。并没有程序启动就生成,因此进程启动无负载。多个单例实例启动顺序自由控制。
缺点:复杂

版本1:(具有线程不安全的问题)

mutex mt;
class Singleton
{
public:
	static Singleton* Instance()
	{	
		if(_instance == nullptr)
		{//如果是多线程则有可能在new的同时其他线程进来if语句,则会生成不同的对象,违背单例模式
			Sleep(100);
			_instance = new Singleton;
		}
		return _instance;
	}
protected:
	Singleton()
	{
	}
	//防拷贝:
	Singleton(Singleton const&); 
 	Singleton& operator=(Singleton const&); 
 
 	// or
 
 	// C++11防赋值
 	Singleton(Singleton const&) = delete; 
 	Singleton& operator=(Singleton const&) = delete; 
private:
	static Singleton* _instance;
};
Singleton* Singleton::_instance = nullptr;//

版本2:(加锁保证了线程安全但是效率低下)

mutex mt;
class Singleton
{
public:
	static Singleton* Instance()
	{
		mt.lock();//因为其实有一部分不满足if条件的线程并不会进入影响线程安全,本不需要等待但是有锁则得依然需要排队等待。这就降低了效率。
		if(_instance == nullptr)
		{
			Sleep(100);
			_instance = new Singleton;
		}
		mt.unlock();
		return _instance;
	}
protected:
	Singleton()
	{
	}
	//防拷贝:
	Singleton(Singleton const&); 
 	Singleton& operator=(Singleton const&); 
 
 	// or
 
 	// C++11防赋值
 	Singleton(Singleton const&) = delete; 
 	Singleton& operator=(Singleton const&) = delete; 
private:
	static Singleton* _instance;
};
Singleton* Singleton::_instance = nullptr;//静态成员类外初始化

版本3:(双检锁)

mutex mt;
class Singleton
{
public:
	static Singleton* Instance()
	{
		//双检锁
		if(_instance == nullptr)
		{//这就解决了版本二的缺点,使得哪些不满足if语句的线程不等待,直接return,这就大大的提高了效率。
			mt.lock();
			if(_instance == nullptr)
			{
				Sleep(100);
				_instance = new Singleton;
			}
			mt.unlock();
		}
		return _instance;
	}
protected:
	Singleton()
	{
	}
	//防拷贝:
	Singleton(Singleton const&); 
 	Singleton& operator=(Singleton const&); 
 
 	// or
 
 	// C++11防赋值
 	Singleton(Singleton const&) = delete; 
 	Singleton& operator=(Singleton const&) = delete; 
private:
	static Singleton* _instance;
};
Singleton* Singleton::_instance = nullptr;//静态成员类外初始化

版本4:(模板类形式)
我们可以把下面的类作为一个模板,当自己需要将不同的类设置为单例模式时,只需要将类名作为模板参数导入即可。例如

class   Test
{
};
void main()
{
       //这样使用即可完成Test类的单例模式设置
       Test *pt1 = LASingletonTemplateBase<Test>::get_instance_ptr();
}

template<typename T>
class LASingletonTemplateBase 
{
    private:
        static T* sm_instance;
    protected://构造方式私有化
        LASingletonTemplateBase()
        {
            assert(sm_instance == 0);
            sm_instance = static_cast<T*>(this);
        }
        virtual ~LASingletonTemplateBase()
        {
            assert(sm_instance != 0);
            sm_instance = 0;
        }

    public:
        static T* get_instance_ptr()
        {
            if(sm_instance == 0)
            {
                sm_instance = new T();
            }
            return sm_instance;
        }

        static T& get_instance_ref()
        {
            if(sm_instance == 0)
            {
                sm_instance = new T();
            }
            return *sm_instance;
        }

        static void remove_instance()
        {
            assert(sm_instance);
            if(sm_instance)
            {
                delete sm_instance;
            }
            assert(sm_instance == 0);
        }
};
template<typename T>
T* LASingletonTemplateBase<T>::sm_instance = 0;//静态成员类内声明类外初始化

总结:单例模式有两种实现模式,分别是饿汉模式和懒汉模式,它们各有优缺点,但实现思路仍然是构造方法私有化,设置静态成员对象是因为只有只有静态成员才可以在类中定义为自身类型成员对象,并且满足了饿汉模式的程序启动对象产生的特性。对于懒汉模式只有设置成了静态属性,才可以在程序一启动就完成初始化,这也就为if条件判断提供了支持。对于懒汉模式的线程不安全问题通过加锁来避免,上述提出几种不同的版本,都是再做不断地优化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值