1. 单例模式简介

  • 目的: 确保一个类只有一个实例,并提供一个全局访问点。
  • 常见用例: 日志记录、配置管理、线程池等。
classDiagram
    class Singleton {
        - static Singleton* instance
        - Singleton()
        + static Singleton* getInstance()
    }
    
    Singleton <|-- Singleton : 使用实例

2. 饿汉模式(Eager Initialization)

  • 描述: 实例在类加载时创建。

  • 代码示例:

    class Singleton {
    private:
        static Singleton* instance;
    
        // 私有构造函数以防止外部实例化
        Singleton() {}
    
    public:
        // 获取实例的静态方法
        static Singleton* getInstance() {
            return instance;
        }
    };
    
    // 在类加载时初始化实例
    Singleton* Singleton::instance = new Singleton();
    
  • 优点: 简单且线程安全,不需要额外的同步措施。

  • 缺点: 即使实例可能不会被使用,也会在类加载时创建,可能导致不必要的资源消耗。

3. 饱汉模式(Lazy Initialization)

  • 描述: 实例仅在需要时才创建。

  • 代码示例:

    class Singleton {
    private:
        static Singleton* instance;
    
        // 私有构造函数以防止外部实例化
        Singleton() {}
    
    public:
        // 获取实例的静态方法
        static Singleton* getInstance() {
            if (instance == nullptr) {
                instance = new Singleton();
            }
            return instance;
        }
    };
    
    // 将静态成员初始化为nullptr
    Singleton* Singleton::instance = nullptr;
    
  • 优点: 实例仅在需要时创建,节省资源。

  • 缺点: 如果不加同步措施,则在多线程环境下可能不安全。

4. 线程安全的考虑

  • 双重检查锁定: 一种使懒汉模式线程安全的技术。

  • 带互斥锁的代码示例:

    #include <mutex>
    
    class Singleton {
    private:
        static Singleton* instance;
        static std::mutex mtx;
    
        Singleton() {}
    
    public:
        static Singleton* getInstance() {
            if (instance == nullptr) {
                std::lock_guard<std::mutex> lock(mtx);
                if (instance == nullptr) {
                    instance = new Singleton();
                }
            }
            return instance;
        }
    };
    
    Singleton* Singleton::instance = nullptr;
    std::mutex Singleton::mtx;
    

5. 总结与最佳实践

  • 方法比较: 何时使用饿汉模式和饱汉模式。
  • 避免陷阱: 特别是在多线程环境中,注意内存管理。