文章目录
(三)创建型模式:单例模式
单例模式在于确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在某些情况下,某些代码组件(如线程池,日志记录器)需要在整个应用程序中共享,使用单例模式可以实现组件资源的复用,并简化系统设计。
单例模式实现方式主要包括饿汉式和懒汉式两种。
饿汉式
饿汉式是指在类加载的时候就创建单例实例,不管后续是否会使用这个实例。
cpp
class Singleton {
private:
static Singleton* instance; // 静态成员变量,属于类本身而不是类的任何特定对象
Singleton() {} // 私有构造函数防止外部实例化
public:
static Singleton* getInstance() { // 全局访问点
return instance;
}
};
Singleton* Singleton::instance = new Singleton(); // 在静态成员变量初始化时创建实例
在多线程环境下,饿汉式是线程安全的,因为实例在类加载时就已经创建好了,不存在并发访问创建实例的问题。
示例:
cpp
#include <iostream>
class Singleton {
private:
static Singleton instance; // 静态实例,在类加载时构造
Singleton() {} // 私有构造函数
public:
static Singleton& getInstance() {
return instance;
}
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
};
Singleton Singleton::instance; // 静态实例初始化
int main() {
Singleton& s1 = Singleton::getInstance();
Singleton& s2 = Singleton::getInstance();
if (&s1 == &s2) {
std::cout << "s1 and s2 are the same instance" << std::endl;
}
s1.doSomething();
return 0;
}
s1 and s2 are the same instance
Doing something...
懒汉式
懒汉式是指在第一次使用时才会创建单例实例,实例的创建被延迟到第一次使用 getInstance()
方法时。
cpp
class Singleton {
private:
static Singleton* instance;
Singleton() {}
public:
static Singleton* getInstance() {
if (instance == nullptr) { // 第一次使用时才会创建单例实例
instance = new Singleton();
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;
示例:
cpp
#include <iostream>
class Singleton {
private:
static Singleton* instance;
Singleton() {} // 私有构造函数
public:
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
~Singleton() {
delete instance; // 注意:在程序结束时需要确保只调用一次析构函数
instance = nullptr;
}
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
};
Singleton* Singleton::instance = nullptr; // 静态成员变量初始化
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance" << std::endl;
}
s1->doSomething();
return 0;
}
s1 and s2 are the same instance
Doing something...
懒汉式在多线程环境下是不安全的,因为多个线程可能同时进入判断条件,导致创建多个实例。因此,需要通过加锁等机制来保证线程安全:
cpp
static std::mutex mtx;
static Singleton* instance;
Singleton* Singleton::getInstance() {
// 使用互斥锁(`std::mutex`)来保证只有一个线程能够创建实例。
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
为了避免每次调用都加锁,产生额外的性能开销,可以在加锁的基础上,进行双重检查:
cpp
static std::mutex mtx;
static Singleton* instance;
Singleton* Singleton::getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
饿汉式 v.s. 懒汉式
在饿汉式单例模式中,单例的实例在程序启动时就立即创建。这种方式的好处在于它的简单性和线程安全性(无需额外的同步机制)。
在懒汉式单例模式中,单例的实例是在首次被需要时才被创建。这种方式的好处在于它可以延迟实例的创建,从而减少程序启动时的资源消耗和初始化时间。