单例模式

什么是单例模式

单例模式是一种常用的设计模式。它能够保证系统中应用该模式的类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

单例模式实现方式

单例模式的实现有两种方式:饿汉模式和懒汉模式。

饿汉模式

该种模式是不管你将来用不用,在程序运行之初就将对象创建好,程序启动时就创建唯一的实例对象。在访问量比较大,或者可能访问的线程比较多时,采用饿汉模式实现,可以实现更好的性能。以空间换时间。

因为我们想在运行之初就要创建好这个唯一实例,所以就要设置一个静态变量,并且把构造函数/拷贝构造函数/赋值运算符重载禁掉(设置成私有,只声明不实现,这样类外就不能调用,且类内也无法调用),这样就保证了实例创建的唯一方式。
再设置一个共有的静态成员函数,返回这个单例的地址,这样就能够保证操纵同一个实例了(设置成静态成员函数是因为,非静态成员函数需要通过对象才能够调用,但是我们又不能通过别的方式创建对象。)

class Hungry
{
public:
	static Hungry* GetInstance()
	{
		return &onlyInstance;
	}
private:
	Hungry() {};
	Hungry(const Hungry&);
	Hungry& operator=(const Hungry&);

	//C++11写法
	Hungry(const Hungry&) = delete;
	Hungry& operator=(const Hungry&) = delete;
private:
	static Hungry onlyInstance;
};
Hungry Hungry::onlyInstance;

int main()
{
	Hungry* a = Hungry::GetInstance();
	return 0;
}

饿汉模式的优点:
1.简单
2.程序启动就设置好了单例,所以饿汉模式是线程安全的。

饿汉模式的缺点:
1.因为单例在程序启动的时候创建,所以可能会导致进程启动慢
2.如果有多个单例类对象实例启动顺序不确定。

懒汉模式

该模式是当首次想要使用单例的时候,才去创建单例。
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好(以时间换空间).

class Lazy
{
public:
	static Lazy* GetInstance()//返回单例
	{   //这里一定要是用双重检查的方式加锁,才能保证效率和线程安全
		if (nullptr == OnlyInstance)
		{
			m_mutex.lock();//加锁
			if (nullptr == OnlyInstance)
			{
				OnlyInstance = new Lazy;
			}
			m_mutex.unlock();//解锁
		}
		return OnlyInstance;
	}
	//实现一个内嵌的垃圾回收类
	class CGarbo
	{
	public:
		~CGarbo()
		{
			if (Lazy::OnlyInstance)
				delete Lazy::OnlyInstance;
		}
	};
	//定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象。
	static CGarbo Garbo;
private:
	//构造函数私有
	Lazy() {};
	//防拷贝
	Lazy(const Lazy&) = delete;
	Lazy& operator=(const Lazy&) = delete;
private:
	static Lazy* OnlyInstance;//单例指针
	static mutex m_mutex;//互斥量
};
Lazy* Lazy::OnlyInstance = nullptr;//初始化
mutex Lazy::m_mutex;
Lazy::CGarbo Garbo;

懒汉模式中,我们用一个静态指针变量来指向单例,静态指针在程序启动时初始化,定义一个GetInstance接口,返回单例指针。

需要注意的是,因为懒汉模式的单例是需要的时候才去创建,所以在首次创建实例的会后要考虑线程安全的问题。

static Lazy* GetInstance()//返回单例
	{   //这里一定要是用双重检查的方式加锁,才能保证效率和线程安全
		if (nullptr == OnlyInstance)//第一次检查
		{
			m_mutex.lock();//加锁
			if (nullptr == OnlyInstance)//第二次检查
			{
				OnlyInstance = new Lazy;
			}
			m_mutex.unlock();//解锁
		}
		return OnlyInstance;
	}

当多个线程并行执行的时候,可能他们都会判断实例未被创建,所以实例就会创建多个,但是这样就不满足单例了。
因此,想让懒汉模式显得线程安全,只需要将堆公共资源的操作原子化就可以了,即加锁,加锁的话让并行的线程变成串行来执行,这样就可以保证这个共有的接口每次只能由一个线程来调度,之后的线程就会被挂起等待,直到前面的线程将锁释放。

双重检查的原因:
第一层检查:
当一个线程运行到第一层检查,如果发现实例已经创建,就直接返回。
如果没有创建则通过第一层检查。进入第一层检查后,让各个线程竞争锁,竞争到锁的线程(A)来进行第二层检查。

第二层检查:
线程A获得锁后,再次判断,如果实例仍然未被创建,则创建实例。如果实例已经被创建,那么就是上次拿到锁的线程(B)创建了实例(B创建的时候A被阻塞在获得锁的地方,A并不知道B先于它获得了锁,如果不再次判断,那么仍然有可能创建多个实例),返回实例。

懒汉模式的优点:
1.第一次要是用单例的时候才去创建,程序启动的时候无负载。
2.多个里启动顺序可以再由控制。

懒汉模式额缺点:
1.代码复杂
2.需要考虑线程安全,由用户加锁。

利用 TensorFlow 训练自己的目标识别器。本文内容来自于我的毕业设计,基于 TensorFlow 1.15.0,其他 TensorFlow 版本运行可能存在问题。.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值