是什么,有什么用
一个类需要保证全局最多同时存在一个实例
有些东西需要保证全局只有一个,例如线程池、缓存、对话框。。。
要点
两种方法
- 懒汉式
- 等到第一次实用的时候才实例化第一个实例
- 饿汉式
- 加载类的时候就实例化第一个实例,之后都是调用
- 缺点 - 没用到该类的时候就会占用系统资源(花时间实例化,占用系统空间),如果占用空间不大或者业务不在乎系统资源的话,可以使用
- 优点 - 无线程安全问题
线程安全问题(仅针对懒汉式
实例化的时候,如果是多线程环境可能存在实例化多次的情况。
java可以通过 synchronized 或者 双重检验锁 的方法来解决
内存安全
防止内存泄漏
CPP实现
实现单例模式,需要
- 一个类静态变量,代表现在的状态,即现在是否存在单例
- 把构造函数放入private中,防止外部胡乱调用
- public中加入getInstance函数,以获取单例
- 如果没实例,实例化一个
- 返回唯一的实例
懒汉式(线程不安全)
- 线程安全问题
- 内存泄漏问题
// code1.
// .h
class Singleton{
private:
static Singleton *unique;
Singleton();
public:
static Singleton *getInstance();
};
// .cpp
Singleton* Singleton::unique = nullptr; // 不写会寄
Singleton::Singleton(){};
Singleton* Singleton::getInstance(){
if(unique ==nullptr)
unique = new Singleton();
return unique;
}
懒汉式(线程安全)
上一种在多线程环境下可能两个或者多个线程刚在 getInstance() 中的 if 判断环节通过后就切换线程,导致多次实例化
双重检验锁
与code1相比,需要加一个 private 锁变量,用于双重检验
// code2.
// .h
class Singleton{
private:
static Singleton *unique;
static std::mutex mutex_; // #include <mutex>
Singleton();
public:
static Singleton *getInstance();
};
// .cpp
std::mutex Singleton::mutex_;
Singleton* Singleton::unique = nullptr;
Singleton::Singleton(){};
Singleton* Singleton::getInstance(){
if(unique ==nullptr){
mutex_.lock();
if(unique ==nullptr){
unique = new Singleton();
}
mutex_.unlock();
}
return unique;
}
饿汉式
线程安全:由于是加载时就声明了,不存在线程安全问题
内存安全:Singleton类里再定义一个类Gc,用Gc类的析构函数跟unique的内存回收进行绑定,然后Singleton类里弄一个静态Gc类小gc,这样小gc析构的时候,就可以在结束的时候完成垃圾回收。
//code3.
// .h
class Singleton{
public:
static Singleton * getInstance();
class Gc{
public:
~Gc();
};
private:
static Singleton *unique;
static Gc gc;
};
// .cpp
Singleton * Singleton::getInstance(){
return unique;
}
Singleton::Gc::~Gc(){
if (unique){
delete unique;
}
}
Singleton * Singleton::unique = new Singleton();
Singleton::Gc Singleton::gc;
参考
- 《大话设计模式》
- 《HeadFirst设计模式》
- c++单例模式
没看,以后万一学了java会看:
java单例模式