设计模式之单例模式

所谓单例模式,顾名思义即只存在一个全局的实例,相对来说是应该最简单的一种设计模式吧。但是虽然单例模式简单,但却有好几种不同的实现方式,这些将在下面提到,现在先亮出单例模式的UML类图。

单例模式有饿汉模式和懒汉模式,这两种的差别主要在对象的创建时机,相同的是一个静态的可供外部获取这个唯一实例对象的接口,一个静态的内部对象指针以及一个内部的构造函数。如下

public:
    static singleton *getInstance();
private:
    singleton();
    static singleton *m_pInstance;

之所以把m_pInstance声明为内部的静态指针,是为了保证唯一的实例对象,因为所有static是所有该类对象共享的。内部的构造函数是为了不让外部对该对象进行实例化,方便控制。getInstance()不用多说了,只有声明为static才能在不指定具体实例的情况下去获取实例。另外,由于静态变量存储在全局区,所以系统会对内存进行回收。

那么所谓饿汉模式,即程序运行时即创建一个对象,完整代码如下:

class singleton
{
public:
    static singleton *getInstance();
private:
    singleton();
    static singleton *m_pInstance;
};

singleton *singleton::m_pInstance = new singleton();

懒汉模式即需要的时候再创建一个对象,完整代码如下:

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

当然这种做法是非线程安全的,试想,当多个线程同时访问getInstance()时,就有可能创建多个实例(尽管只有一个指针)。很简单,既然线程不安全的话就加锁嘛,于是写下了这样的代码(lock()和unlock()都是瞎写的):

static singleton *getInstance()
{
    lock();
    if(nullptr == m_pInstance)
        m_pInstance = new singleton;
    unlock();
    return m_pInstance; 
}

static singleton *getInstance()
{
    if(nullptr == m_pInstance)
    {  
        lock();
        m_pInstance = new singleton;
        unlock();
    }
   
    return m_pInstance; 
}

首先,对于第一种写法,每次进入函数都要加锁解锁,开销无疑是巨大且没必要的。因为仅仅在没有实例的时候才会出现线程不安全的情况。对于第二种写法,因为加锁的位置不对,仍存在线程不安全的情况。

实际上线程安全的写法可以这样写:

static singleton* getInstance()
{
    if(nullptr == m_pInstance)
    {
        lock();
        if(nullptr == m_pInstance)
            m_pInstance = new singleton;
        unlock();
    }

    return m_pInstance;
}

windows API及linux下也提供了一些函数,可以实现线程安全,以下仅有linux下的代码,Windows API对应的函数为(msdn进不去,忘了是啥了,改天更新上来吧),使用方法相似:

//linux
class singleton
{
private:
    singleton();
    static void init()
    {
        m_pInstance = new singleton;
    }

    static singleton *m_pInstance;
    static pthread_once_t m_once;

public:
    static singleton* getInstance()
    {
        pthread_once(&m_once, init);
        return m_pInstance;
    }
}

singleton *singleton::m_pInstance = nullptr;
pthread_once_t singleton::m_once = PTHREAD_ONCE_INIT;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值