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

单例模式是一种创建型设计模式,确保一个类只有一个实例并提供全局访问点。主要解决资源频繁创建与销毁的问题,适用于需要控制实例数量、节省资源的场景。实现方式包括懒汉式(延迟初始化,线程不安全)和饿汉式(类加载时初始化,线程安全)。懒汉式可通过加锁或内部静态变量实现线程安全,饿汉式天生线程安全。
摘要由CSDN通过智能技术生成

一、单例模式
1、概念:
只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
这种设计模式属于创建型模式,它提供了一种创建对象的最佳方式
**关键点:**①一个类只有一个实例(最基本的)
②它必须自行创建这个实例
③它必须给所有其他对象提供这个实例
**意图:**保证一个类仅有一个实例,并提供一个访问它的全局访问点
**主要解决:**一个全局使用的类频繁地创建与销毁
**何时使用:**当你想控制实例数目,节省系统资源的时候
**如何解决:**判断系统是否已经有这个单例,如果有则返回,没有则创建
**关键代码:**构造函数是私有的
应用实例:
①一个班级只有一个班主任。
②Window是多进程多线程的,在操作一个文件的时候,就不可避免的出现多个进程或线程同时操作一个文件的现象,所以所有的文件的处理 必须通过唯一的实例来进行。
③一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一文件
优点:
①在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如电子学院首页页面缓存)
②避免对资源的多重占用(比如写文件操作)
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景:
①要求生产唯一的序列号
②WEB中的计数器,不用每次刷新都在数据库中加一次,用单例先缓存起来
③创建的一个对象需要消耗的资源过多,比如I/O与数据库的连接
单例模式的实现:
构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的动作由一个public的类方法代劳,该方法也返回单例类唯一的实例。
一、简单

class Singleton {
private:
	Singleton(){}
	static Singleton *p;
public:
	static Singleton *instance();
};
Singleton *Singleton::p = nullptr;
Singleton * Singleton::instance() {
	if (p == nullptr) {
		p = new Singleton();
	}
	return p;
}

二、

#include<iostream>
#include<thread>
using namespace std;
class Singleton {
private:
	Singleton(){}//构造函数private
	static Singleton *single;
public:
	static Singleton *GetSingleton();
};
Singleton *Singleton::single = nullptr;
Singleton *Singleton::GetSingleton() {
	if (single == nullptr) {
		single = new Singleton;
	}
	return single;
}
int main() {
	//只有调用GetSingleton时,类才会new出对象
	Singleton *s1 = Singleton::GetSingleton();
	Singleton *s2 = Singleton::GetSingleton();
	if (s1 == s2) {
		cout << "s1==s2" << endl;//输出s1==s2
	}
	else {
		cout << "s1!=s2" << endl;
	}
	return 0;
}

2、两种主要实现方式:
**懒汉:**顾名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化(懒汉模式本身是线程不安全的)

**饿汉:**单例类定义的时候就进行实例化。(本身是线程安全的)
如何选择:
懒汉:在访问量较小的时候,采用懒汉实现。这是以时间换空间。
饿汉:由于要进行线程的同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉模式实现,可以实现更好的性能。这是以空间换时间。
①:懒汉模式(类加载时不初始化)
线程不安全,怎么办?最直观的方法是:加锁。
方法1:加锁的经典懒汉实现

class Singleton {
private:
	Singleton() {
		pthread_mutex_init(&mutex);
	}
	static Singleton *p;
public:
	static pthread_mutex_t mutex;
	static Singleton *instance();
};
pthread_mutex_t Singleton::mutex;
Singleton *Singleton::p = nullptr;
Singleton *Singleton::instance() {
	if (p == nullptr) {
		pthread_mutex_lock(&mutex);
		if (p == nullptr) {
			p = new Singleton();
		}
		pthread_mutex_unlock(&mutex);
	}
	return p;
}

方法2:内部静态变量的懒汉实现
在instance函数里定义一个静态的实例,也可以保证拥有唯一实例,在返回时只需要返回其指针就可以了。(这种方法非常简单,强推)

class Singleton {
private:
	Singleton() {
		pthread_mutex_init(&mutex);
	}
public:
	static pthread_mmutex_t mutex;
	static Singleton *initance();
};
pthread_mutex_t Singleton::mutex;
Singleton *Singleton::initance() {
	pthread_mutex_lock(&mutex);
	static Singleton obj;
	pthread_mutex_unlock(&mutex);
	return &obj;

}

②:饿汉模式(在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快)
饿汉模式本身就是线程安全的,不用加锁

class Singleton{
private:
	Singleton(){}
	static Singleton *p;
public:
	static Singleton *initance();
};
Singleton *Singleton::p = new Singleton;
Singleton *Singleton::initance() {
	return p;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值