何为单利模式和设计模式
单例模式:就是是一经典的、常见的、常考的设计模式
设计模式:根据一些经典常见的场景,给定了一些解决办法,这就是设计模式
分类
饿汉模式(空间换时间):不考虑线程安全问题—>在程序初始化阶段就完成资源申请初始化
代码!!!!
template <typename T>
class Singleton {
static T data;
public:
static T* GetInstance() {
return &data;
}
};
懒汉模式(时间换空间)
template <typename T>
class Singleton {
static T* inst;
public:
static T* GetInstance() {
if (inst == NULL) {
inst = new T();
}
return inst;
}
};
存在线程不安全缺陷,第一次调用GetInstance时候,如果两个线程同时调用,可能会创建出两份T对象实例化。但是后续再次调用就没有问题。
所以进行了改进:
考虑线程安全问题,在资源申请前进行了加锁保护。
// 懒汉模式, 线程安全
template <typename T>
class Singleton {
volatile static T* inst; // 需要设置 volatile 关键字, 否则可能被编译器优化.
static std::mutex lock;
public:
static T* GetInstance() {
if (inst == NULL) { // 双重判定空指针, 降低锁冲突的概率, 提高性能.
lock.lock(); // 使用互斥锁, 保证多线程情况下也只调用一次 new.
if (inst == NULL) {
inst = new T();
}
lock.unlock();
}
return inst;
}
};
总结一下,懒汉模式实现的五个步骤:
1.保证内存中资源只有一份—>使用static修饰
2.使用时再去加载资源初始化—>定义的时候并不直接定义对象,而是定义指针,访问的时候为NULL则new一个资源
3.防止编译器过度优化—>使用volatile关键字修饰
4.考虑线程安全问题,在资源申请及判断前加锁保护(防止多线程访问资源被new了多次)
5.需要考虑效率问题:资源已经加载初始化,后期获取操作句柄时,每次都要加锁解锁两次,并且多执行同时访问还有可能造成冲突,使用二次判空来解决。