声明: 本博客参考C语言中文网和优秀博客总结得出:
(1)C语言中文网链接
(2)优秀博客链接

单例模式的定义: 指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。
在计算机系统中,还有 Windows 的回收站、操作系统中的文件系统、多线程中的线程池、打印机的后台处理服务、应用程序中的对话框、系统中的缓存等常常被设计成单例。
单例模式在现实生活中的应用也非常广泛,例如公司 CEO、部门经理等都属于单例模型。

单例模式特点:
(1)单例类只有一个实例对象;
(2)该单例对象必须由单例类自行创建;
(3)单例类对外提供一个访问该单例的全局访问点。
为了满足以上三个特点,我们通常对类进行以下设计:
(1)将构造函数设置为私有。(这样外界就不可以随便实例化对象了)
(2)有一个指向实例的静态指针。
(3)用一个静态成员方法(或者全局友元函数,只不过我们通常都是用静态成员方法)来实例化对象,并且对实例化进行控制,只实例化一次,让静态指针指向实例,第一次进行实例操作,后面都直接返回已经指向实例的静态指针变量本身。

单例模式的优点和缺点:
单例模式的优点:
(1)单例模式可以保证内存里只有一个实例,减少了内存的开销。
(2)可以避免对资源的多重占用。
(3)单例模式设置全局访问点,可以优化和共享资源的访问。
单例模式的缺点:
(1)单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
(2)在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
(3)单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

一、懒汉模式

根据代码看问题:

//单例模式-懒汉模式
class singleton_idler
{public:static singleton_idler* Get_objectptr()//静态成员方法{if (object_ptr == nullptr){mtx.lock();if (object_ptr == nullptr){object_ptr = new singleton_idler;}mtx.unlock();}return object_ptr;}int& Get_val(){return m_val;}private:singleton_idler() {}static singleton_idler* object_ptr;static int m_val;static mutex mtx;
};mutex singleton_idler::mtx;
int singleton_idler::m_val = 10;
singleton_idler* singleton_idler::object_ptr = nullptr;int main()
{singleton_idler* ptr1 = singleton_idler::Get_objectptr();cout << "ptr1指向的实例地址为:" << ptr1 << "\t" << "m_val地址为:"<< &(ptr1->Get_val()) << "\t" << "m_val值为:" << ptr1->Get_val() << endl;singleton_idler* ptr2 = singleton_idler::Get_objectptr();cout << "ptr1指向的实例地址为:" << ptr2 << "\t" << "m_val地址为:"<< &(ptr2->Get_val()) << "\t" << "m_val值为:" << ptr2->Get_val() << endl;return 0;
}

运行结果:

可以通过两个指针指向的实例的地址看出来,两个指针指向的是同一个实例,整个过程就只实例化出来一个对象。
这就是懒汉模式,你需要的时候才给你创建一个实例,而且后面你用的就只有这一个实例,创建一个实例后,就不创建了。
构造函数被设置成私有,就是为了让创建对像的权力只交给下面这个静态函数:

static singleton_idler* Get_objectptr()//静态成员方法{if (object_ptr == nullptr){mtx.lock();if (object_ptr == nullptr){object_ptr = new singleton_idler;}mtx.unlock();}return object_ptr;}

这个静态方法是整个懒汉模式的核心,而这个静态方法的核心就是创建对象,对象的创建被层层保护起来,就是为了确保只实例化一次。
如果object_ptr不为nullptr,说明已经创建过对象了(注意,object_ptr是静态指针变量),那么就直接返回指针本身就好了。如果object_ptr没有创建过对象,那么object_ptr就是nullptr(注意代码中,静态指针成员变量object_ptr,我们在类外初始化为nullptr了),那么就会进到第一个if语句,而进到第一个if语句加锁是因为,在多线程的情况下,在没有实例化对象的情况下,可能两个地方同时调用这个静态方法,那么此时两个地方用的是同一个object_ptr都是nullptr,那么都会进到第一层for循环,所以第一层for循环里面加锁了,此时只能一个线程拿到锁,进到里面。那么为什么锁里面又有个if语句呢? 注意,此时一个线程拿到锁了,进去了,还一个线程没有拿到锁,就阻塞在mtx.lock()这个地方了,当进去的线程实例化完成后,释放锁,在mtx.lock()被阻塞的线程就会拿到锁,如果此时没有里面那一层if语句,这个线程就会重新new一个对象,将object_ptr重新指向这个对象,这只是两个线程可能出现的问题,如果更多个线程进到第一个if语句,就会new很多次对象了。当然,如果已经object_ptr已经不为nullptr了,那么没有进到第一个if语句的线程,第一个if语句就进不去了。所以最安全的办法就是锁外锁内都有一个if语句。
当然,在博客上还可以看到一种写法:

static singleton_idler* Get_objectptr()//静态成员方法{mtx.lock();if (object_ptr == nullptr){object_ptr = new singleton_idler;}mtx.unlock();return object_ptr;}

将锁外面的if语句去掉了,这样也是线程安全的,因为锁只能被一个线程拿到,当第一个实例化对象之后,其他线程拿到锁进去之后,if语句判断就会发现object_ptr不为nullptr,就不会再去实例化了。
但是这段代码和上面两个if语句的代码有点区别,就是当已经实例化过对象之后,多个线程同时进到这个静态方法里面之后,这个时候就会只有一个线程拿到锁,去判断if语句,而其他线程就会都阻塞到mtx.lock这里,然后前面的线程拿到锁判断完if语句之后,解锁,被阻塞的这些线程会抢锁,有一个线程抢到,进入到里面,进行if语句判断,其他线程阻塞到mtx.lock()这里…
而两个if语句的代码,当已经实例化过后,就不存在阻塞到mtx.lock()这里的情况了,因为第一个if语句判断完不为nullptr之后就直接return object_ptr了。

二、饿汉模式

饿汉模式和单例模式的区别在于,懒汉模式在你需要的时候才去创建,饿汉模式利用静态指针变量存在数据区的特点,在一开始就直接创建一个实例(在线程创建之前),所以饿汉模式的线程肯定是安全的。
代码示例:

//单例模式-懒汉模式class singleton_hungry
{public:static singleton_hungry* Get_objectptr(){return object_ptr;}
private:singleton_hungry() { cout << "创建一个实例" << endl; }~singleton_hungry() { cout << "析构一个实例" << endl; }//为了让实例整个程序运行的时候都存在,所以不允许实例自己调动析构函数//因为对于饿汉模式来说,实例的创建只能在编译时创建一次,如果析构了,后面不可能再创建了//除非重新编译运行static singleton_hungry* object_ptr;
};singleton_hungry* singleton_hungry::object_ptr = new singleton_hungry;//直接实例化int main()
{singleton_hungry* ptr1 = singleton_hungry::Get_objectptr();singleton_hungry* ptr2 = singleton_hungry::Get_objectptr();return 0;
}

运行结果:

由于实例在一开始创建,而且在这之后不再可能创建,除非重新编译运行,为了不让实例自己析构,我们就将析构函数写成私有。
将析构函数写成私有之后,那么实例就只能等程序运行结束,自动回收实例占有的堆空间了。然后如果想要在程序运行结束之前析构实例,就成了难题,(其实我在想,我们将析构函数写成私有就是为了让实例在整个程序运行的时候都存在,然后将析构函数写成私有之后,我们却又在想怎么析构实例,那么我们为了让实例在整个程序运行阶段都存在而把析构函数写成私有的意义呢?

设计模式——单例模式(懒汉模式,饿汉模式)相关推荐

  1. 【设计模式:单例模式】单例模式01:饿汉模式

    单例模式:饿汉模式 正文开始@Assassin 目录: 单例模式:饿汉模式 1. 什么是设计模式? 2. 单例设计模式: 2.1 什么是单例模式? 2.2 单例模式应用实例: 1. 什么是设计模式? ...

  2. 单例模式的原理/懒汉模式/饿汉模式以及不同版本的单例模式程序

    单例模式 单例模式定义 懒汉模式与饿汉模式 懒汉模式 饿汉模式 懒汉模式和饿汉模式的区别 懒汉模式的不同版本 版本一 版本二 版本三 版本四 单例模式定义 保证一个类仅有一个实例,并提供一个该实例的全 ...

  3. java 单例模式 懒汉和饿汉

    单线程下的单例模式 定义: 确保一个类只有一个实例,并提供一个全局访问点. 单例代码: package wfb.pattern;public class Singleton {private stat ...

  4. 【设计模式】之单例模式中的饿汉模式和懒汉模式

    本文内容:什么是单例模式,单例的作用,饿汉模式,懒汉模式的安全与非安全的实现,饿汉模式与懒汉模式的区别. 什么是单例模式? 单例模式:保证一个类,仅有一个实例.提供一个访问它的全局访问点. 单例的作用 ...

  5. 单例模式下的懒汉和饿汉模式

    1 //单例模式---懒汉模式 2 public class Apple{ 3 //创建一个成员,在内存中只有一个拷贝 4 private static Apple apple = null; 5 p ...

  6. java单例设计模式懒汉_Java设计模式之单例设计模式(懒汉、饿汉)

    [toc] Java设计模式之单例设计模式(懒汉.饿汉) 相信面试过的初中级Java开发的朋友可能都有遇到过单例设计模式的笔试题吧,如果之前没有背下来或者不理解,可以看看下面这篇文章,应该足够应付笔试 ...

  7. 单例模式——懒汉与饿汉

    前言:设计模式是在不断编程中前人所总结的"兵书",将可能面对的大部分编程需求归纳总结为固定的模式,而单例模式则是最常见的设计模式之一. 设计模式 设计模式(Design Patte ...

  8. 【C++】单例模式(懒汉、饿汉)

    1.什么是单例模式? 顾名思义,单例模式就是在这个单例类确保只有一个对象被创建.也就是说这个类只能实例化一个对象. 特征:1.单例类最多只能有一个实例: 2.单例类必须自己创建自己唯一的实例: 3.单 ...

  9. 单例模式懒汉、饿汉和登记

    转载自  JAVA设计模式之单例模式 本文继续介绍23种设计模式系列之单例模式. 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记 ...

  10. 23种设计模式C++源码与UML实现--单例模式中的饿汉模式和懒汉模式

    单例模式 单例模式是一种对象创建模式,使用单例模式,可以保证为一个类生成唯一的实例对象.也就是说在这个程序空间该类只有一个实例对象. GoF对单例的定义:保证一个类.只有一个实例存在,同时提供对该实例 ...

最新文章

  1. 【深度学习】深度神经网络框架的探索(从Regression说起)
  2. [pytorch] 官网教程+注释
  3. 寄存器指令MIPS 寄存器介绍
  4. mysql linux64安装----转载
  5. js 报错:object is not a function
  6. 数字滤波器设计工具_数字设计师和代理商的资源和工具
  7. 电阻分压可以当作电源供电吗
  8. HTML img src图片路径不存在,则显示一张默认图片的方法
  9. 用AI打电话骗走22万,Python编写的软件,克隆你的语音只需5秒!
  10. 社会网络分析法(Social Network Analysis)中矩阵二值化阈值的确定
  11. uni.showtoast不显示的问题,可能是因为uni uni.showloding uni.showtoast 冲突
  12. Linux设置鼠标滑轮速度
  13. [ 个人住房担保委托贷款(住房公积金贷款)]
  14. linux 计算百分比,计算百分比的分析函数
  15. TIA博途中OB86组织块的功能和使用方法
  16. c语言long型是什么,c语言long类型是什么意思
  17. 一个简单的BitTorrent客户端实现(二):种子文件解析及信息保存
  18. 爬猫眼电影top100
  19. 海康威视软件测试实习岗面试(已拿offer)
  20. Python 短信通知系统开发实战

热门文章

  1. [转]UTF-8 GBK UTF8 GB2312 之间的区别和关系
  2. 更新部分字段 NHibernate
  3. HarmonyOS之深入解析WLAN的功能和使用
  4. PyTorch - torchvision - datasets
  5. 【Tiny4412】Tiny4412编译和烧写uboot
  6. 【Linux】一步一步学Linux——enable命令(212)
  7. 图片和input不对齐_pdf到png再到mp4短视频:不需要工具,2个指令1键搞定
  8. 执行应用程序出现: No such file or directory
  9. 乘积最大子数组—leedcode152
  10. matlab::mex::ArgumentList outputs的创建