博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++设计模式之单例模式
阅读量:6650 次
发布时间:2019-06-25

本文共 3120 字,大约阅读时间需要 10 分钟。

单例模式:用来创建独一无二的,只能够有一个实例的对象。 单例模式的结构是设计模式中最简单的,但是想要完全实现一个线程安全的单例模式还是有很多陷阱的,所以面试的时候属于一个常见的考点~

单例模式的应用场景:有一些对象其实只需要一个,比如:线程池,缓存,对话框,处理偏好设置和注册表的对象,日志对象,充当打印机,显卡等设备的驱动程序对象。这些对象只能够拥有一个实例,如果创建出了多个实例,就会导致一些程序的问题。程序的行为异常,资源使用的过量,或者导致不一致的结果。常用来管理共享的资源,比如数据库的连接或者线程池。

我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的动作由一个public的类方法代劳,该方法也返回单例类唯一的实例。

class singleton{protected:    singleton(){}private:    static singleton* p;public:    static singleton* instance();};singleton* singleton::p = NULL;singleton* singleton::instance(){    if (p == NULL)        p = new singleton();    return p;}

这是一个很棒的实现,简单易懂。但这是一个完美的实现吗?不!该方法是线程不安全的,考虑两个线程同时首次调用instance方法且同时检测到p是NULL值,则两个线程会同时构造一个实例给p,这是严重的错误!同时,这也不是单例的唯一实现!

2 懒汉与饿汉

  单例大约有两种实现方法:懒汉与饿汉。

    • 懒汉:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化,所以上边的经典方法被归为懒汉实现;
    • 饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。

  特点与选择:

    • 由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
    • 在访问量较小时,采用懒汉实现。这是以时间换空间。

3 线程安全的懒汉实现

  线程不安全,怎么办呢?最直观的方法:加锁。

  • 方法1:加锁的经典懒汉实现:

class singleton{protected:    singleton()    {        pthread_mutex_init(&mutex);    }private:    static singleton* p;public:    static pthread_mutex_t mutex;    static singleton* initance();};pthread_mutex_t singleton::mutex;singleton* singleton::p = NULL;singleton* singleton::initance(){    if (p == NULL)    {        pthread_mutex_lock(&mutex);        if (p == NULL)            p = new singleton();        pthread_mutex_unlock(&mutex);    }    return p;}

互斥的同步会导致性能的降低,即使p已经不为空了,每次还是需要加锁,这样操作花费就比较多,性能必定比较差。

  • 方法2:内部静态变量的懒汉实现

  此方法也很容易实现,在instance函数里定义一个静态的实例,也可以保证拥有唯一实例,在返回时只需要返回其指针就可以了。推荐这种实现方法,真得非常简单。

class singleton{protected:    singleton()    {        pthread_mutex_init(&mutex);    }public:    static pthread_mutex_t mutex;    static singleton* initance();    int a;};pthread_mutex_t singleton::mutex;singleton* singleton::initance(){    pthread_mutex_lock(&mutex);    static singleton obj;    pthread_mutex_unlock(&mutex);    return &obj;}

4 饿汉实现

  饿汉实现本来就是线程安全的,不用加锁。

class singleton{protected:    singleton()    {}private:    static singleton* p;public:    static singleton* initance();};singleton* singleton::p = new singleton;singleton* singleton::initance(){    return p;}

 

*另外一种提升因为同步导致的性能变差的方法称为“双重检验加锁”。方法如下:

思路是只有在第一次创建的时候进行加锁,当_instance不为空的时候就不需要进行加锁的操作,这样就可以提升性能~

class Lock{private:          mutex mtex;public:    Lock(mutex m) : mtex(m)    {        mtex.Lock();    }    ~Lock()    {        mtex.Unlock();    }};class Singleton {public:    static Singleton* getInstance();    //析构的时候释放资源~    ~Singleton() {        if( (_instance != NULL)            delete _instance;    }protected:    Singleton();private:    static Singleton* _instance;    static mutex m;} Singleton *Singleton::_instance = NULL;Singleton* Singleton::getInstance() {    //check 之前进行临界区加锁操作    //双重检验加锁    if(_instance == NULL ) {        Lock lock(m);        if( _instance == NULL) {            _instance = new Singleton();        }    }    return _instance;}

 

转自:

https://www.cnblogs.com/weixliu/p/3900764.html

http://www.cnblogs.com/qiaoconglovelife/p/5851163.html

 

转载于:https://www.cnblogs.com/zzdbullet/p/10479312.html

你可能感兴趣的文章
架构中的7个设计原则
查看>>
SDUT 3374 数据结构实验之查找二:平衡二叉树
查看>>
php的错误级别
查看>>
eclipse修改android项目的apk包名类名
查看>>
斐讯路扫地机器人怎么关机_扫地机器人使用方法,使用教程
查看>>
java 二元一次方程式_JAVA求解一元一次二次方程
查看>>
python与r语言处理excel数据_R语言第一章数据处理基础①读取EXEL表格数据
查看>>
上一家单位离职的原因_你从上一家公司辞职的原因是什么?几类标准答案
查看>>
ip扫描的原理是什么_什么是高防IP,高防IP的原理是什么样的
查看>>
import 快捷键 自动调整顺序_深入探讨 Python 的 import 机制:实现远程导入模块
查看>>
k型热电偶材料_设备篇——辊道窑之热电偶
查看>>
上车是什么意思_“上车饺子下车面”,是什么意思?看完心里暖暖的
查看>>
anaconda安装python3消失_Python学习第47课-安装Python以及anaconda介绍
查看>>
centos7中编译安装nodejs_Docker(一)CentOS7中安装Docker视频教程
查看>>
ug装配绕轴旋转_UG模具设计培训就到新科教育
查看>>
服务器闪退_马洛斯服务器|高端玩家游戏建议
查看>>
linux7 udev eth,CENTOS 7 udev:renamed network interface eth0 to eth1 eno16777736
查看>>
五子棋对弈程序c语言,五子棋程序纯C语言版.doc
查看>>
c语言二维数组程序实例讲解,C语言二维数组的处理实例
查看>>
c语言程序报告函数关系描述,《C语言程序设计》实验报告
查看>>