搜索
您的当前位置:首页正文

[设计模式]单例模式

来源:独旅网

单例模式

单例模式是一种常用的设计模式,用于确保一个类只能有一个实例化对象。这种模式的优点在于可以节约系统资源、方便进行对象的管理和控制。

实现方式

在单例模式中,类只有一个实例化对象,并且该对象可以通过一个全局操作方法进行访问。这个操作方法需要满足以下特点:

  • 该方法必须是静态的。
  • 该方法必须返回一个类的唯一实例对象。
  • 该方法必须保证只有一个实例对象被创建,并且该对象可以被多个客户端共享。

懒汉模式

在懒汉模式中,实例化对象的过程会被推迟到第一次访问该对象时。这种方式的优点是可以减少系统开销,但缺点是在多线程环境中可能会出现竞争条件,导致出现多个实例化对象。

class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};
 Singleton* Singleton::instance = nullptr;

在上面的示例中,我们使用了静态成员变量和静态成员函数实现了单例模式,采用了懒汉式的实现方式。但是,上面的代码没有考虑线程安全的问题,解决方法有:

1.在getInstance函数中加锁
class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
public:
    static Singleton* getInstance() {
        static std::mutex mtx;
        std::lock_guard<std::mutex> lock(mtx);
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};
 Singleton* Singleton::instance = nullptr;

在上面的示例中,我们在getInstance函数中使用了std::mutex来实现了线程同步,并保证了只有一个Singleton对象。

2.使用双重检查锁定(Double Checked Lock)方式
class Singleton {
private:
     static Singleton* instance;
     Singleton() {}
     static std::mutex mtx;
public:
     static Singleton* getInstance() {
         if(instance == nullptr) {
             std::lock_guard<std::mutex> guard(mtx);
             if(instance == nullptr) {
                 instance = new Singleton();
             }
         }
         return instance;
     }
     ~Singleton() { delete instance; }
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

在上面的示例中,我们使用std::mutex来实现了线程同步,并使用双重检查锁定方式避免了不必要的开销。每次获取Singleton对象时,第一次检查instance是否为空,如果为空则加锁,再次检查instance是否为空,如果为空则new一个Singleton对象。返回新创建的对象,并解锁。这种方式可以保证只有一个Singleton对象,并且是线程安全的。

3.静态局部变量实现懒汉模式

还有一种方法是使用静态局部变量的方式来实现懒汉模式,它可以避免使用互斥锁的方式实现线程同步,比双重检查锁定方式更为高效。

class Singleton {
public:
     static Singleton* getInstance() {
         static Singleton instance;
         return &instance;
     }
     ~Singleton() {}
private:
     Singleton() {}
     Singleton(const Singleton&) = delete;
     Singleton& operator=(const Singleton&) = delete;
};

需要注意的是,使用静态局部变量实现懒汉模式需要考虑线程安全问题,虽然该方法使用了静态局部变量,但是静态局部变量的初始化是线程不安全的,因此需要确保线程安全。

饿汉模式

在饿汉模式中,实例化对象的过程是在程序运行时进行的,即在类的初始化阶段就已经完成了实例化对象的过程。这种方式的优点是可以避免竞争条件,但缺点是如果对象比较大,会导致系统资源浪费。

class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
public:
    static Singleton* getInstance() {
        return instance;
    }
};
 Singleton* Singleton::instance = new Singleton();

在上面的示例中,我们使用了在类的初始化阶段完成静态成员变量的初始化实现了饿汉模式,不需要考虑线程安全问题。

需要注意,以上的示例都是针对单线程或者多线程环境下不需要频繁创建和销毁单例对象的情况。如果需要频繁创建和销毁单例对象,可以考虑使用对象池等方式。

使用场景

单例模式通常在以下场景中使用:

  • 当需要确保只有一个对象实例并且该对象需要在多个地方进行访问时。
  • 当需要控制资源使用并避免过多的系统资源占用时。
  • 当需要使用全局变量时,可以将其实现为单例模式。

总结

单例模式是一种常用的设计模式,用于确保只有一个实例化对象的创建,并且该对象可以被多个客户端共享。在使用单例模式时需要注意保证线程安全和避免出现死锁等问题。

因篇幅问题不能全部显示,请点此查看更多更全内容

热门图文

Top