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

【JavaEE初阶】懒汉模式与饿汉模式及指令重排序问题

目录

📕 单例模式

🌳 饿汉模式

🚩 线程安全

🎍 懒汉模式

🚩 懒汉模式-单线程版

🚩 懒汉模式-多线程版

🎄 指令重排序


📕 单例模式

单例模式是一种经典的设计模式,是校招中最常考的设计模式之一.

那么啥是设计模式呢?

  • 设计模式好比象棋中的 “棋谱”. 红方当头炮, 黑方马来跳. 针对红方的一些走法, 黑方应招的时候有一些固定的套路. 按照套路来走局势就不会吃亏.
  • 软件开发中也有很多常见的 “问题场景”. 针对这些问题场景, 大佬们总结出了一些固定的套路. 按照这个套路来实现代码, 也不会吃亏.

那么什么是单例模式呢?

  • 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
  • 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
  • 单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。

注意:

  1. 单例类只能有一个实例。

  2. 单例类必须自己创建自己的唯一实例。

  3. 单例类必须给所有其他对象提供这一实例

单例模式具体的实现方式, 又分成 “饿汉” 和 “懒汉” 两种,掌握这两种应付面试+日常开发完全足够

🌳 饿汉模式

饿汉模式,就是它很饿,它的对象早早的就创建好了

由于是 static 修饰的,所以由 static 修饰的成员初始化时机是在类加载的时候,类具体啥时候加载,后面讲到JVM的时候再细说,可简单的认为就是在JVM一启动的时候就立即加载了(其实有变数)。

现在呢我们是有一个private这样的成员,光一个private成员还不够,要写一个public这样的方法供其他代码进行使用。

后序呢,在代码里面要想用到这个类的实例,就直接通过 getinstance 来获取,而不是重新去new

接下来,上述代码是已经把唯一实例准备好了,万一其他代码又new了这个类的实例怎么办,所以我们就需要禁止外部代码来创建该类的实例,在Singleton类里面在创建一个构造方法即可,里面可以什么都不写,但是必须要由private修饰(核心)。

在main方法调用:

尝试在main方法中new,就会编译出错:  提示说该方法是私有的,不能访问

注意:

  • 优点:没有加锁,执行效率会提高。

  • 缺点:类加载时就初始化,浪费内存

🚩 线程安全

🎍 懒汉模式

🚩 懒汉模式-单线程版

代码:

饿汉模式的代码突出的就是一个急切,只要程序启动就创建出实例,而懒汉模式是在第一次调用getinstance的时候创建实例,啥时候调用就啥时候创建,如果不调用就不创建。

main方法调用:还是一样,不管调用几次都是同一个实例

尝试去new,也会出现语法错误:

线程不安全:

🚩 懒汉模式-多线程版

上面的懒汉模式的实现是线程不安全的.

  • 线程安全问题发生在首次创建实例时.如果在多个线程中同时调用getInstance方法,就可能导致创建出多个实例.
  • 一旦实例已经创建好了,后面再多线程环境调用getInstance就不再有线程安全问题了(不再修改 instance 了)

我们可以加上 synchronized 可以改善这里的线程安全问题

代码:

注意:锁这个东西不是说加了一定安全,也不是不加一定不安全,这里仍然使存在线程安全问题的

把加锁操作放到 if 外面,就是把 if 和 new 打包成一个原子操作:

问题:

只要在加锁之前再次判断 ->if ( instance == null ) 即可,就能使这个代码线程安全即效率不受影响

通过双重 if 避免了不可重复读负面影响,避免了重复创建对象。

注意:之前谈到的 volatile 的优化问题,不是100%触发的,可能触发,可能不触发,上述代码考虑的是不触发优化的情况,如果触发优化的情况,需要再来一手 volatile。避免出现优化情况下的内存可见性问题,确保说第一个线程的修改操作一定会被后序线程读到。

🎄 指令重排序

上述讲到给变量加上 volatile 是因为涉及到内存可见性问题,另一方面加上 volatile 也能够解决指令重排序引起的线程安全问题。

指令重排序呢也是编译器的一种优化策略。

注意:编译器优化有多种策略,把读内存优化到读寄存器,指令重排序,循环展开,条件分支预测......这些都是优化策略,也是属于比较垂直的领域,对于大部分程序员不需要知道,属于专门负责开发编译器/开发操作系统内核一小部分人研究。

那对于上篇文章写的懒汉模式的代码来说,如果不给这里的 instance 加上 volatile 的话,此时是有可能在多线程环境下出现指令重排序引起的线程安全问题。

那具体是怎么引起的 ?

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Windows图形界面(GUI)-MFC-C/C++ - 列表框(ListBox) - CListBox
  • 分享一个基于微信小程序的旅游自助拼团系统(源码、调试、LW、开题、PPT)
  • C#MQTT协议应用
  • 解决idea debug/run 启动项目一闪而过的问题
  • Docker 设置代理
  • vscode+linux+opencv环境配置
  • 使用ollama取代openai的api进行graphRAG失败记录
  • 《Milvus Cloud向量数据库指南》—Milvus Cloud赋能Ivy.ai:解锁大数据潜力,加速AI创新
  • 低代码: 系统开发准备之确定一般开发流程,需求分析,复杂度分析,标准开发流程
  • C#初级——字典Dictionary
  • 【深度学习】什么是混合精度训练?缩放因子 S 的选择
  • 探索编程世界:大学新生的最佳入门路径与学习方法
  • 字节序大小端
  • 无人机之导航系统篇
  • 单片机如何使用超声波传感器进行距离测量
  • hexo+github搭建个人博客
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 3.7、@ResponseBody 和 @RestController
  • Android 控件背景颜色处理
  • Android组件 - 收藏集 - 掘金
  • C++11: atomic 头文件
  • docker python 配置
  • js继承的实现方法
  • ReactNativeweexDeviceOne对比
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • select2 取值 遍历 设置默认值
  • supervisor 永不挂掉的进程 安装以及使用
  • Vue2.0 实现互斥
  • 从0到1:PostCSS 插件开发最佳实践
  • 从零开始的无人驾驶 1
  • 第十八天-企业应用架构模式-基本模式
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 前端面试题总结
  • 巧用 TypeScript (一)
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 如何用vue打造一个移动端音乐播放器
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • gunicorn工作原理
  • ​Python 3 新特性:类型注解
  • ​十个常见的 Python 脚本 (详细介绍 + 代码举例)
  • ###C语言程序设计-----C语言学习(6)#
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (13)Hive调优——动态分区导致的小文件问题
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (二)斐波那契Fabonacci函数
  • (二)原生js案例之数码时钟计时
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (论文阅读40-45)图像描述1
  • (十三)Flink SQL
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • .java 9 找不到符号_java找不到符号
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖