单例模式--详解及代码实现

某些类, 只应该具有一个对象(实例), 就称之为单例.
在很多服务器开发场景中, 经常需要让服务器加载很多的数据 (上百G) 到内存中. 此时往往要用一个单例的类来管理这些数据。

饿汉模式:吃完饭, 立刻洗碗, 这种就是饿汉方式. 因为下一顿吃的时候可以立刻拿着碗就能吃饭.
懒汉模式:吃完饭, 先把碗放下, 然后下一顿饭用到这个碗了再洗碗, 就是懒汉方式.

懒汉模式最核心的思想是 延迟加载 ,能够优化服务器的启动速度,因为不需要实例化出对象。

饿汉方式实现单例模式

//饿汉模式
template 
class singleton1
{
  static T data;
public:
  static T* GetInstance()
  {
    return &data;
  }
};

只要通过 singleton1 这个包装类来使用 T 对象,则一个进程中只有一个 T 对象的实例。

懒汉模式实现单例模式

//线程安全的懒汉模式
template 
class singleton2
{
  volatile static T* inst;//需要设置volatile关键字,否则可能被编译器优化
  static std::mutex lock;
public:
  static T* GetInstance()
  {
    if(inst==nullptr) //双重判定空指针,降低锁冲突的概率,提高性能
    {
      lock.lock();  //使用互斥锁,保证多线程情况下也只调用一次new
      if(inst==nullptr)
      {
        inst = new T();
      }
      lock.unlock();
    }
    return inst;
  }
};

我们想象一下,如果不采用线程安全版本的懒汉模式,当第一次调用 GetInstance 的时候,如果两个线程绝对同步的进入判断时(这里的绝对同步是指当没有实例化出对象时,两个线程同时到达进行判断,那么都将通过判断),可能会创建出两份 T 对象的实例,这里就违背了单例模式的原则。

因此,为了线程安全,要进行双重判断空指针,降低锁冲突的的概率,提高性能。
这里外面的判断是为了提高效率,里面的判断是为了线程安全。

你可能感兴趣的:(linux)