本文主要介绍各种单例模式的原理,及其不同的实现方法。实现语言为C++
定义:单例模式–保证一个类仅有一个实例,并提供一个访问它的全局访问点。
这篇文章介绍以下四种单例模式的类型,也是较为常用的。
1 饿汉式单例
class Singleton {
private:
// Singleton() = default; // 自动生成默认构造函数
Singleton() {
cout << "Singleton construct\n";
}
Singleton(const Singleton& s) = delete; // 禁用拷贝构造函数
Singleton& operator=(const Singleton& s) = delete; // 禁用拷贝赋值操作符
static Singleton m_singleton;
public:
static Singleton* getInstance(){
return &m_singleton;
}
};
Singleton Singleton::m_singleton;
2 懒汉式单例
class Singleton {
private:
// Singleton() = default; // 自动生成默认构造函数
Singleton() { // 构造函数 会影响局部静态变量, 不能用隐式的构造函数
cout << "Singleton construct\n";
}
Singleton(const Singleton& s) = delete; // 禁用拷贝构造函数
Singleton& operator=(const Singleton& s) = delete; // 禁用拷贝赋值操作符
public:
static Singleton* getInstance(){
static Singleton s_singleton; // C++11线程安全, C++11之前不是线程安全 __cxa_guard_acquire 和 __cxa_guard_release
return &s_singleton;
}
};
3 双锁型单例模式
/* 双检查锁,但由于内存读写reorder不安全 因为C++创建对象时,会执行1、分配内存,2 调用构造,3 赋值操作三步操作,
然而现代CPU和编译器高并发下可能会进行乱序重排操作,因而创建对象new CSingleton的第2步可能会晚于第3步进行指令调用,
因而导致出现未定义的的行为。*/
class Singleton {
private:
static Singleton *m_singleton;
static mutex m_mutex;
Singleton() = default;
Singleton(const Singleton& s) = default;
Singleton& operator=(const Singleton& s) = default;
class GarbageCollector {
public:
~GarbageCollector() {
cout << "~GarbageCollector\n";
if (Singleton::m_singleton) {
cout << "free m_singleton\n";
delete Singleton::m_singleton;
Singleton::m_singleton = nullptr;
}
}
};
static GarbageCollector m_gc;
public:
void *getSingletonAddress() {
return m_singleton;
}
static Singleton* getInstance() {
if (Singleton::m_singleton == nullptr){
m_mutex.lock(); // 加锁,保证只有一个线程在访问线程内的代码
if (Singleton::m_singleton == nullptr) { //再次检查
m_singleton = new Singleton(); // 对象的new不是原子操作 1、分配内存,2 调用构造,3 赋值操作,到第3步的时候才是m_singleton非空
// 1、分配内存,2 赋值操作 3 调用构造,到第2步的时候才是m_singleton非空
}
m_mutex.unlock();//解锁
}
return m_singleton;
}
};
Singleton* Singleton::m_singleton = nullptr;
mutex Singleton::m_mutex;
Singleton::GarbageCollector Singleton::m_gc;
4 线程安全型单例
//线程安全的懒汉式单例
class Singleton {
private:
static Singleton *m_singleton;
static mutex m_mutex;
Singleton() = default;
Singleton(const Singleton& s) = delete; // 禁用拷贝构造函数
Singleton& operator=(const Singleton& s) = delete; // 禁用拷贝赋值操作符
class GarbageCollector {
public:
~GarbageCollector() {
cout << "~GarbageCollector\n";
if (Singleton::m_singleton) {
cout << "free m_singleton\n";
delete Singleton::m_singleton;
Singleton::m_singleton = nullptr;
}
}
};
static GarbageCollector m_gc;
public:
static Singleton* getInstance() { // 加锁的粒度大,效率较低, 对高并发的访问
m_mutex.lock(); // 加锁,保证只有一个线程在访问下面的语句
if (Singleton::m_singleton == nullptr){
// std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //休眠,模拟创建实例的时间
m_singleton = new Singleton();
}
m_mutex.unlock();//解锁
return m_singleton;
}
};
Singleton* Singleton::m_singleton = nullptr;
mutex Singleton::m_mutex;
Singleton::GarbageCollector Singleton::m_gc;