单例模式的懒汉模式和饿汉模式
2017-07-30 12:30
274 查看
单例模式:
要求:
1、单例类只有唯一一个实例对象
2、单例类提供唯一获取这一实例接口GetInstance()
重点:解决线程安全问题
设计难点:
一、饿汉模式(编译加载阶段完成初始化实例):
只需设计一个GetInstance()方法,并直接初始化唯一实例对象(可在方法外初始化也可在方法内初始化)。
二、懒汉模式(在运行时初始化实例):
1、在运行时第一次调用该实例时再初始化。
2、考虑线程安全问题:即初始化时在new前加lock_guard类型的锁,保证new一系列操作的原子性,该锁必须定义为static,保证所有线程用一把锁。RAII 该锁出作用域自动释放。
3、考虑内存优化问题:内存优化可能打乱new的几个步骤的顺序,使用内存栅栏MemoryBarrier()解决该问题。
4、定义一个内部类,在作用域结束前调用该类对象,从而调用该对象的析构,释放单例对象,保证内存不泄露的问题。
共同设计难点:
1、必须将构造、拷贝构造、operator=写在private限定符内,后两个只声明不实现。
2、必须将唯一实例对象和GetInstance方法定义为static的。
懒汉模式和饿汉模式对比:
懒汉模式:
1、在运行代码时才初始化实例,需要解决线程安全问题。
2、加载速度快,运行获取对象慢
3、写法复杂,但所有场景均使用
饿汉模式:
1、在编译加载时初始化实例,不会产生线程安全问题。
2、加载速度慢,运行获取对象速度快
3、写法简单,但适用性受限(如动态库)
代码实现:
要求:
1、单例类只有唯一一个实例对象
2、单例类提供唯一获取这一实例接口GetInstance()
重点:解决线程安全问题
设计难点:
一、饿汉模式(编译加载阶段完成初始化实例):
只需设计一个GetInstance()方法,并直接初始化唯一实例对象(可在方法外初始化也可在方法内初始化)。
二、懒汉模式(在运行时初始化实例):
1、在运行时第一次调用该实例时再初始化。
2、考虑线程安全问题:即初始化时在new前加lock_guard类型的锁,保证new一系列操作的原子性,该锁必须定义为static,保证所有线程用一把锁。RAII 该锁出作用域自动释放。
3、考虑内存优化问题:内存优化可能打乱new的几个步骤的顺序,使用内存栅栏MemoryBarrier()解决该问题。
4、定义一个内部类,在作用域结束前调用该类对象,从而调用该对象的析构,释放单例对象,保证内存不泄露的问题。
共同设计难点:
1、必须将构造、拷贝构造、operator=写在private限定符内,后两个只声明不实现。
2、必须将唯一实例对象和GetInstance方法定义为static的。
懒汉模式和饿汉模式对比:
懒汉模式:
1、在运行代码时才初始化实例,需要解决线程安全问题。
2、加载速度快,运行获取对象慢
3、写法复杂,但所有场景均使用
饿汉模式:
1、在编译加载时初始化实例,不会产生线程安全问题。
2、加载速度慢,运行获取对象速度快
3、写法简单,但适用性受限(如动态库)
代码实现:
#pragma once #include<cassert> #include<mutex> #include& 4000 lt;windows.h> using namespace std; //懒汉模式 --- 在运行时创建单例对象 namespace LAZY { class singleton { public: static singleton* GetInstance() { if (_init == NULL) //只有第一次创建对象时走一次 { //加锁,保证new和赋值为原子的 RAII----出作用域释放锁 lock_guard<mutex> lock(_mut); //new的步骤: //1.operator new开空间 //2.调构造函数 //3.赋值 //_init = new singleton; //由于内存优化可能将2、3优化顺序颠倒-----采用内存栅栏防止优化 singleton* tmp = new singleton; MemoryBarrier(); //内存栅栏---保证栅栏之前的必定比栅栏之后的先运行 _init = tmp; } return _init; } void print() { cout << "singleton:" << _a << endl; } //内部类,完成单例对象的释放工作 struct GC { ~GC() { DelInstance(); } }; static void DelInstance() { lock_guard<mutex> lock(_mut); if (_init != NULL) { cout << "delete" << endl; delete _init; _init = NULL; } } private: singleton() :_a(0) {} ~singleton() { //释放数据库等操作 } //只声明不实现 singleton(const singleton&); singleton& operator=(const singleton&); int _a; //定义静态成员和锁 static singleton* _init; static mutex _mut; //静态锁保证全局是一把锁---保证new和赋值的原子性 }; singleton* singleton::_init = NULL; mutex singleton::_mut; void Test() { singleton::GetInstance()->print(); singleton::GetInstance()->print(); singleton::GetInstance()->print(); getchar(); } //创建gc对象,出作用域时释放_init static singleton::GC gc; } //饿汉模式 --- 编译加载时初始化唯一实例对象 namespace HUNGRY { class singleton { public: //获取单例对象必须是静态方法 static singleton& GetInstance() { //assert(_init); //return *_init; static singleton _init; return _init; } void print() { cout << "singleton:" << _a << endl; } private: singleton() :_a(0) {} //将拷贝构造operator=设置为防拷贝 singleton(const singleton&); singleton& operator=(const singleton&); int _a; //单例类成员变量 //static singleton* _init; }; //初始化单例对象 //singleton* singleton::_init = new singleton; void Test() { singleton::GetInstance().print(); singleton::GetInstance().print(); singleton::GetInstance().print(); getchar(); } }
相关文章推荐
- 懒汉模式和饿汉模式
- 懒汉单例模式与饿汉单例模式
- Singleton 单例模式(懒汉方式和饿汉方式)
- java 单例模式之线程安全的饿汉模式和懒汉模式
- 单例模式 (懒汉,饿汉,双重校验锁)
- C++的单例模式与线程安全单例模式(懒汉/饿汉)
- Singleton 单例模式(懒汉方式和饿汉方式)
- java的设计模式之单利设计模式(饿汉和懒汉)
- 单例模式有五种写法:懒汉、饿汉、双重检验锁、静态内部类、枚举。
- C++的单例模式与线程安全单例模式(懒汉/饿汉)
- java中的懒汉单例模式和饿汉单例模式
- 单例模式有五种写法:懒汉、饿汉、双重检验锁、静态内部类、枚举。
- C++的单例模式与线程安全单例模式(懒汉/饿汉)
- 设计模式-单例模式(懒汉、饿汉)
- C++中的单例模式(懒汉模式、饿汉模式及线程安全问题)
- 单例模式中的“饿汉”和“懒汉”的深入分析
- 单例模式的两种方式:饿汉模式与懒汉模式
- 设计模式——单例模式之“饿汉模式”与“懒汉模式”
- 单例模式(懒汉方式和饿汉方式)+双重检验锁
- C++的单例模式与线程安全单例模式(懒汉/饿汉)