在软件设计模式中,单例模式(Singleton Pattern)是一种常用的创建型模式,确保一个类只有一个实例,并提供全局访问点。单例模式的两种主要实现方式是懒汉式(Lazy Initialization)和饿汉式(Eager Initialization)。
饿汉式单例模式
饿汉式单例模式在类加载时就创建单例实例。由于实例在类加载时就创建,所以是线程安全的,但即使实例从未被使用,也会在程序启动时占用一定的资源。
实现示例(饿汉式)
#include <iostream>
class Singleton {
private:
static Singleton* instance;
// 私有构造函数,防止外部实例化
Singleton() {
std::cout << "Singleton instance created (Eager Initialization)." << std::endl;
}
public:
// 禁用复制构造函数和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 获取实例的静态方法
static Singleton* getInstance() {
return instance;
}
};
// 在类加载时就初始化实例
Singleton* Singleton::instance = new Singleton();
int main() {
Singleton* singleton1 = Singleton::getInstance();
Singleton* singleton2 = Singleton::getInstance();
// 输出相同的地址,表示是同一个实例
std::cout << "Singleton 1 address: " << singleton1 << std::endl;
std::cout << "Singleton 2 address: " << singleton2 << std::endl;
return 0;
}
懒汉式单例模式
懒汉式单例模式在第一次使用时才创建单例实例。为了保证线程安全,通常需要引入同步机制。
实现示例(懒汉式,线程不安全)
#include <iostream>
class Singleton {
private:
static Singleton* instance;
// 私有构造函数,防止外部实例化
Singleton() {
std::cout << "Singleton instance created (Lazy Initialization)." << std::endl;
}
public:
// 禁用复制构造函数和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 获取实例的静态方法
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* singleton1 = Singleton::getInstance();
Singleton* singleton2 = Singleton::getInstance();
// 输出相同的地址,表示是同一个实例
std::cout << "Singleton 1 address: " << singleton1 << std::endl;
std::cout << "Singleton 2 address: " << singleton2 << std::endl;
return 0;
}
实现示例(懒汉式,线程安全)
#include <iostream>
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mutex;
// 私有构造函数,防止外部实例化
Singleton() {
std::cout << "Singleton instance created (Thread-safe Lazy Initialization)." << std::endl;
}
public:
// 禁用复制构造函数和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 获取实例的静态方法
static Singleton* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mutex); // 锁定互斥锁
if (instance == nullptr) { // 再次检查实例是否为空
instance = new Singleton();
}
}
return instance;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;
int main() {
Singleton* singleton1 = Singleton::getInstance();
Singleton* singleton2 = Singleton::getInstance();
// 输出相同的地址,表示是同一个实例
std::cout << "Singleton 1 address: " << singleton1 << std::endl;
std::cout << "Singleton 2 address: " << singleton2 << std::endl;
return 0;
}
饿汉式与懒汉式的比较
特点 | 饿汉式(Eager Initialization) | 懒汉式(Lazy Initialization) |
---|---|---|
实例创建时机 | 类加载时 | 第一次使用时 |
线程安全性 | 天生线程安全 | 需要额外的线程安全措施 |
资源利用率 | 如果实例长期不使用,会浪费内存 | 资源利用率高,只有在需要时才创建实例 |
实现难度 | 简单 | 需要考虑线程安全问题 |
选择哪种实现方式
- 饿汉式适用于类加载后立即需要使用实例的情况,且对内存占用不敏感。
- 懒汉式适用于实例创建开销较大,且不一定每次都需要使用实例的情况,但需要考虑线程安全问题。
根据实际需求选择合适的单例模式实现方式,可以更好地优化程序的性能和资源使用。