当前位置: 首页 > news >正文

一文带你深入了解懒汉模式和饿汉模式

一文带你深入了解懒汉模式和饿汉模式


文章目录

  • 一文带你深入了解懒汉模式和饿汉模式
    • 一、饿汉模式 (Hungry Singleton)
      • 饿汉模式特点
      • 工作原理
    • 二、懒汉模式 (Lazy Singleton)
      • 懒汉模式特点
      • 双重检查锁原理
    • 三、两种模式对比
    • 四、懒汉模式的潜在问题
      • 问题1:内存泄漏
      • 问题2:指令重排风险(C++11之前)
    • 五、C++11 后的最佳实践(Meyers' Singleton)
      • 优点:
    • 六、单例模式使用场景
    • 七、总结
  • 总结

这是一个经典的单例模式实现,包含了饿汉模式懒汉模式两种版本。你的代码非常完整,我来详细解释这两种模式的原理、优缺点以及你代码中的关键细节。

一、饿汉模式 (Hungry Singleton)

classhunger{public:statichunger*getinstance(){return&_instance;// 直接返回静态对象的地址}private:hunger(){}// 私有构造hunger(consthunger&)=delete;hunger&operator=(consthunger&)=delete;private:statichunger _instance;// 静态成员变量};// 在类外初始化(程序启动时创建)hunger hunger::_instance;

饿汉模式特点

特性说明
初始化时机程序启动时(main函数执行前)就创建好实例
线程安全天然线程安全(初始化在单线程阶段完成)
访问速度最快(直接返回已存在的对象)
资源占用无论是否使用,都会占用资源

工作原理

intmain(){// 程序启动时,静态对象 _instance 已经构造完成hunger*p1=hunger::getinstance();hunger*p2=hunger::getinstance();// p1 == p2,同一个实例return0;}

二、懒汉模式 (Lazy Singleton)

classlazy{public:staticlazy*getinstance(){if(_instance==nullptr)// 第一次检查(不用锁){_mtx.lock();// 加锁if(_instance==nullptr)// 第二次检查(双重检查锁){_instance=newlazy();}_mtx.unlock();}return_instance;}private:lazy(){}lazy(constlazy&)=delete;lazy&operator=(constlazy&)=delete;private:staticmutex _mtx;// 互斥锁staticlazy*_instance;// 指针};// 初始化lazy*lazy::_instance=nullptr;mutex lazy::_mtx;

懒汉模式特点

特性说明
初始化时机第一次调用 getinstance()时才创建
线程安全需要额外机制保证(你用了双重检查锁)
资源占用按需创建,节省资源
性能第一次调用有锁开销,后续无锁

双重检查锁原理

你的代码使用了经典的双重检查锁模式:

if(_instance==nullptr)// 第一重检查:避免每次调用都加锁{_mtx.lock();// 只有第一次才进入锁if(_instance==nullptr)// 第二重检查:防止多个线程同时通过第一重检查{_instance=newlazy();}_mtx.unlock();}

三、两种模式对比

对比维度饿汉模式懒汉模式
初始化时机程序启动时首次使用时
线程安全天然安全需要手动保证
实现复杂度简单复杂(需要锁)
启动速度较慢(要构造单例)
运行效率高(无锁)高(除第一次外无锁)
内存占用总是占用按需占用
适用场景单例一定会被使用单例可能不被使用

四、懒汉模式的潜在问题

问题1:内存泄漏

你的代码没有考虑释放单例对象。虽然程序结束时会由操作系统回收,但严格来说应该有释放机制。

// 改进:添加一个嵌套的析构辅助类classlazy{public:staticlazy*getinstance(){...}private:// 辅助析构的内部类classDeleter{public:~Deleter(){if(lazy::_instance){deletelazy::_instance;lazy::_instance=nullptr;}}};staticDeleter _deleter;// 程序结束时自动析构};

问题2:指令重排风险(C++11之前)

_instance=newlazy();// 实际分三步:// 1. 分配内存// 2. 调用构造函数// 3. 赋值给 _instance// 编译器或CPU可能重排为 1->3->2!

C++11 后可以用std::call_oncestd::atomic解决:

#include<atomic>#include<mutex>classlazy{public:staticlazy*getinstance(){lazy*tmp=_instance.load(std::memory_order_acquire);if(tmp==nullptr){std::lock_guard<std::mutex>lock(_mtx);tmp=_instance.load(std::memory_order_relaxed);if(tmp==nullptr){tmp=newlazy();_instance.store(tmp,std::memory_order_release);}}returntmp;}private:staticstd::atomic<lazy*>_instance;staticstd::mutex _mtx;};

五、C++11 后的最佳实践(Meyers’ Singleton)

C++11 保证静态局部变量的初始化是线程安全的,所以最简单安全的懒汉模式是:

classSingleton{public:staticSingleton&getInstance(){staticSingleton instance;// 静态局部变量(C++11 线程安全)returninstance;}private:Singleton(){}~Singleton(){}Singleton(constSingleton&)=delete;Singleton&operator=(constSingleton&)=delete;};

优点:

  • 线程安全(C++11 保证)
  • 无锁,性能好
  • 代码极简
  • 自动析构

六、单例模式使用场景

场景说明
配置管理器全局唯一的配置对象
日志系统所有模块写同一个日志文件
线程池全局唯一的线程池实例
数据库连接池避免创建多个连接池
文件系统统一的文件操作接口

七、总结

你的代码完整展示了两种经典单例实现:

模式关键代码优点缺点
饿汉static hunger _instance;线程安全,简单可能浪费资源
懒汉双重检查锁按需创建实现复杂,有风险

面试建议

  • 先说出两种模式的区别
  • 解释懒汉模式为什么要双重检查锁
  • 提到 C++11 后的 Meyers’ Singleton 作为最佳实践
  • 说明单例的适用场景和注意事项(如禁止拷贝)

总结

这篇文章是作者搜集大量面经和资料这里出来的。感谢你的支持
作者wkm是一名中国矿业大学(北京) 大一的新生,希望得到你的关注
如果可以的话,记得一键三联!

http://www.jsqmd.com/news/450167/

相关文章:

  • 实测时把dt调成0.01秒,调参比谈恋爱还费劲
  • 2026年分析凯旋螺杆泵,哪家厂家的产品更值得推荐 - 工业推荐榜
  • 我是Claw_第22章_信任与责任
  • 钛丝驱动应用案例(NiTiDrivetech)-仿生机器人-手
  • 网络安全毕业设计2026开题答疑
  • 计算机毕业设计之基于SpringBoot的毕业生离校管理系统
  • 2026最全AI论文写作软件排名:这几款工具被高校悄悄推荐
  • 探寻2026年江苏靠谱的静音房设计定制企业哪家好 - 工业设备
  • ARM 快速乘法指令深度解析:从指令集到底层实现
  • 选购噪音房设计定制,全国范围内哪家企业更? - 工业品网
  • 计算机毕业设计之springboot网上书城平台系统的设计与实现
  • 桌面Agent大战续篇:不止数据分析师,产品经理也要失业了
  • 基于Python+ai技术的教务辅助 学生考试成绩分析系统
  • AI新时代下前端开发工程师如何自处?
  • 盒马鲜生礼品卡闲置?教你几分钟搞定变现小妙招 - 团团收购物卡回收
  • 基于阶梯碳交易成本的‘含电转气-碳捕集(P2G-CCS)耦合的综合能源系统低碳经济优化调度‘...
  • 送货单打印软件包|销售单打印工具
  • 033数码产品抢购系统-springboot+vue
  • 乐然净品厨房湿巾好用吗,适合深圳长沙家庭清洁吗 - 工业品牌热点
  • 图像编辑之 Qwen模型应用
  • 当测试思维遇见千年文物:一个被忽视的技术蓝海
  • 类和对象进阶:初始化列表的标准使用、隐式类型转换、static成员、友元型的使用、匿名对象、及小点:内部类与对象拷贝时的编译器优化
  • 天地通 SMT 贴片加工靠谱吗?5个维度深度评测
  • 2026年雅卓宁波机床展排名情况,分析价值、布局及交通条件 - mypinpai
  • 别再瞎找了!AI论文网站 千笔·专业论文写作工具 VS 云笔AI,专为本科生打造!
  • dq0法谐波电流检测法,关于并联型APF/有源电力滤波器/Matlab/Simulink的仿真...
  • 【AI】 AI 发展史:从图灵测试到大模型时代的技术演进
  • CSP-S 2025 员工招聘(employ)
  • 【大数据毕设源码分享】基于springboot+数据可视化的天气可视化分析系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • IPC-CH-65B:PCB/组件清洗工艺指南(中文版)完整版【可下载】 最新版解读与实用工艺指南