单例模式(SingleTon):保证一个类只有一个实例,并提供一个访问它的全局访问点。
由类自身负责保存它的唯一实例,并且保证没有其他实例可以被创建,而不是外部判断。
- C++ 实现
class SingleTon {
private:
SingleTon() {
std::cout << "constructor called!" << std::endl;
}
SingleTon(SingleTon&) = delete;
SingleTon& operator=(const SingleTon&) = delete;
static SingleTon* instance;
public:
~SingleTon() {
std::cout << "destructor called!" << std::endl;
}
static SingleTon* GetInstance() {
if (instance == nullptr) {
instance = new SingleTon;
}
return instance;
}
};
SingleTon* SingleTon::instance = nullptr; // 懒汉单例
/*SingleTon* SingleTon::intance = new SingleTon ;* // 饿汉单例
- 利用局部静态变量,实现更简洁的单例模式(懒汉模式)
class SingleTon {
private:
SingleTon() {
std::cout << "constructor called!" << std::endl;
}
SingleTon(SingleTon&) = delete;
SingleTon& operator=(const SingleTon&) = delete;
public:
~SingleTon() {
std::cout << "destructor called!" << std::endl;
}
static SingleTon* GetInstance() {
static SingleTon instance;
return &instance;
}
};
懒汉模式:在第一次使用的时候创建唯一实例。
饿汉模式:在自己被加载的时候将自己实例化,不管是否使用,先创建唯一实例。以后只需要返回唯一实例,这样也是线程安全的。
线程安全的单例模式
简单的单例模式在多线程访问的时候,可能产生多少实例。我们给进程加锁来避免资源竞争,保证只产生一个实例。
当线程位于代码临界区,确保其他线程不能进入临界区,一直等待直到互斥量被释放。
class SingleTon {
private:
SingleTon() {
std::cout << "constructor called!" << std::endl;
}
SingleTon(SingleTon&) = delete;
SingleTon& operator=(const SingleTon&) = delete;
static SingleTon* instance;
static std::mutex mutex;
public:
~SingleTon() {
std::cout << "destructor called!" << std::endl;
}
static SingleTon* GetInstance() {
if (instance == nullptr) { //已经创建实例后直接返回对象,避免每次都加锁
std::unique_lock<std::mutex> lck(mutex); //上锁,避免多线程竞争
if (instance == nullptr) { //再次判断,保证多个线程几乎同时到达临界区,也只创建一个实例
instance = new SingleTon;
}
}
return instance;
}
};
SingleTon* SingleTon::instance = nullptr; // 懒汉模式
std::mutex SingleTon::mutex;
代码使用“双重锁定Double-Check Locking”:不让每个线程都加锁,只有在实例未创建的时候加锁,同时也能保证线程安全。