单例模式的几种实现

本文详细介绍了C++中单例模式的实现方法,包括常规单例模式、加锁单例模式、双重检查锁定模式以及懒汉和饿汉模式,并探讨了它们在多线程环境下的线程安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先说明:“singleton”是一个单词,不是一个复合词。

接下来步入正题。对于单例模式无论是“饿汉”还是“懒汉”都必须要有的是:

一.私有构造函数

二.声明静态单例对象

如果是“懒汉”的话为了写出好的没有 bug的单例代码还应注意

三.构造单例对象之前要加锁(lock一个静态的object对象)

四.需要两次检测单例实例是否已经被构造,分别在锁之前和锁之后

1、常规单例模式实现:

/*方法一:实现Singleton模式常规方法*/
class Singleton{
private:
	Singleton() { }              //关键点0:构造函数私有
	static Singleton *p;         //关键点1:声明单例对象是静态的      
public:
	static Singleton * instance();
};
Singleton * Singleton::instance() {   //通过静态方法构造对象
	if (p == NULL)                //关键点2:判断单例对象是否被构造
		p = new Singleton();
	return p;
}
Singleton * Singleton::p=NULL; //注意!

分析:这段代码在通常情况下是可以运行的。但是遇到多线程可能就不行了。考虑两个线程同时调用instance方法且同时检测到pNULL,显然此时就不是单例了。

既然说到了多线程,显然能想到加锁来处理。于是有:

2、常规单例模式加锁:

//方法二:在常规常规方法基础上加锁
class Singleton {
private:
	Singleton() {                     //关键点0:构造函数私有,对锁初始化。
		pthread_mutex_init(&mutex,NULL);
	}                
	static Singleton *p;              //关键点1:声明单例对象是静态的
public:
	static pthread_mutex_t mutex;     //创建一个互斥锁
	static Singleton *instance();
};

Singleton *Singleton::instance() {
	if (p == NULL) {                  //关键点2:判断单例对象是否被构造
		pthread_mutex_lock(&mutex);   //关键点3:加线程锁
		p = new Singleton;
		pthread_mutex_unlock(&mutex); //解锁
	}
	return p;
}
Singleton* Singleton::p = NULL;
pthread_mutex_t Singleton::mutex;

分析:由于延迟加载或者缓存的原因,一次判断仍然不能保证只创建一个单例。于是乎有下面双重检查锁定模式。

3、双重检查锁定:

//方法三:双重检查锁定模式
class Singleton {
private:
	Singleton() {                     //关键点0:构造函数私有(并对锁初始化)。
		pthread_mutex_init(&mutex, NULL);
	}
	static Singleton *p;              //关键点1:声明单例对象是静态的
public:
	static pthread_mutex_t mutex;     //创建一个互斥锁
	static Singleton *instance();
};

Singleton *Singleton::instance() {
	if (p == NULL) {                  //关键点2:判断单例对象是否被构造
		pthread_mutex_lock(&mutex);   //关键点3:加线程锁
		if (p == NULL) {              //关键点4:二次判断是否已经初始化
			p = new Singleton;
		}
		pthread_mutex_unlock(&mutex); //解锁
	}
	return p;
}
Singleton* Singleton::p = NULL;
pthread_mutex_t Singleton::mutex;

分析:至此代码就能确保单例,是可以接受的。但是这样的代码实现起来比较复杂,容易出错。

于是引出了“懒汉模式”和“饿汉模式”。

4、“懒汉模式”和“饿汉模式

懒汉:万不得已才实例化类。延时加载——以时间换空间。

饿汉:一上来就把对象给new出来。非延时加载——以空间换时间

显然上面的代码都是“懒汉模式”,那嫩否给出一个“饿汉模式”的例子呢?当然

5、饿汉模式

//方法4:饿汉模式_这样锁也不用加了。
/*人家还没要,自己就忍不住的先准备好了,如饥似渴,所以叫饿汉模式*/
class Singleton {
private:
	Singleton() {}                     //关键点0:构造函数私有。          
	static Singleton* p;               //关键点1:声明静态单例对象是
public:
	static Singleton* instance() {     //关键点3:需要的时候直接返回就好了。
		return p;
	}
};
Singleton* Singleton::p=new Singleton(); //关键点2:直接先创建了。

分析:代码非常短,效果非常好,连锁都不用了。

其实只要记住后面两个实现就可以了。如果更注重空间性能就选择“双重检查锁定”,如果更注重时间性能则果断选择“饿汉模式”。

老生常谈C++的单例模式与线程安全单例模式(懒汉/饿汉)_C 语言_脚本之家

http://blog.jobbole.com/109449/

C++单例模式 - Deaglepc - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焱齿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值