单例模式有哪几种实现,如何保证线程安全?
单例模式常见有:
懒汉式(线程不安全,需改进)
#include <iostream>
class Singleton { // 单例类,成员有一个静态指针和一个私有构造函数
private:
static Singleton* instance; // 静态实例指针,用于存储单例对象的地址,外部无法访问
Singleton() {} // 私有构造函数,防止外部实例化
public:
// 禁止拷贝和赋值操作,确保单例对象不会被复制或赋值,从而保证其唯一性
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* getInstance() { // 获取单例对象实例,如果实例不存在则创建
// 这里是懒汉式单例模式,只有在第一次调用时才创建实例
if (instance == nullptr) { // 只有在实例为空时创建
instance = new Singleton(); // 创建单例对象
// 这里可以添加线程安全的代码来确保在多线程环境下也能正确创建单例对象
}
return instance;
}
void doSomething() {
std::cout << "Lazy Singleton instance (Not Thread Safe)" << std::endl;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* singleton = Singleton::getInstance(); // 获取单例对象实例
singleton->doSomething();
system("pause");
return 0;
}
双重检查锁定(线程安全)
#include <iostream>
#include <mutex> // 引入互斥锁头文件
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;// 静态互斥锁,用于保证线程安全,防止多个线程同时创建实例
Singleton() {}// 私有构造函数,防止外部实例化
public:
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx); // 锁住互斥锁,确保线程安全
// 这里是双重检查锁定,确保在多线程环境下也能正确创建单例对象,因为在锁住互斥锁后,可能会有其他线程也在等待创建实例
// 所以需要再次检查实例是否为空,以避免重复创建实例,相对于懒汉式单例模式,双重检查锁定可以提高性能
// 因为只有在第一次调用时才会创建实例,后续调用只会返回已创建的实例
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
void doSomething() {
std::cout << "Double-Checked Locking Singleton instance" << std::endl;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx; // 初始化静态成员变量
// 注意:在多线程环境下,静态成员变量的初始化需要保证线程安全,可以使用互斥锁来实现
int main() {
Singleton* singleton = Singleton::getInstance();
singleton->doSomething();
system("pause");
return 0;
}
静态局部变量(c++11推荐)
#include <iostream>
class Singleton {
private:
Singleton() {} // 私有构造函数
public:
// 禁止拷贝和赋值操作
Singleton(const Singleton&) = delete; // 禁止拷贝构造函数
Singleton& operator=(const Singleton&) = delete;// 禁止赋值操作符,operator=是赋值操作符,delete是删除,表示禁止使用这个操作符
static Singleton& getInstance() {
static Singleton instance; // 静态局部变量,线程安全 (C++11 保证)
return instance;//instance类型是Singleton的引用类型,返回的是一个引用
}
void doSomething() {
std::cout << "Static Local Variable Singleton instance" << std::endl;
}
};
int main() {
Singleton& singleton = Singleton::getInstance();//引用获取单例对象实例,singleton是一个引用类型的对象,指向单例对象
singleton.doSomething();
return 0;
}
// 这个实现是线程安全的,因为静态局部变量在 C++11 及以后的标准中是线程安全的。