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

双检查锁下的单例懒汉模式

1、什么是单例懒汉模式?

单例模式:保证一个类在JVM中只有一个实例,并提供一个全局访问点。
懒汉模式:在第一次调用获取实例方法时才创建对象,而不是类加载时。核心优点是延迟加载,节省资源;缺点是线程不安全。
举个例子:

publicclassSingleton{privatestaticSingletoninstance1;publicstaticSingletongetInstance1(){if(instance1==null){instance1=newSingleton();}returninstance1;}

对象实例创建流程:

  • 先分配一片足够放下Singleton对象的空间,赋默认值。
  • 再执行构造方法初始化对象。
  • 建立关联,对象引用指向该对象实例。

2、单例懒汉模式下的问题

问题:CPU或者编译器会将第2、3步的指令重排序,单线程下不会有问题。多线程下问题有两个:
T1 如果先执行3,还没执行2的时候,T2 判断得知对象引用不为空,直接返回了未初始化的对象,导致错误。
会导致重复创建,违背单例模式。如果T1在创建对象的过程中,另一个线程T2判断得知instance1==null,那么它会进入对象创建流程,从而创建重复对象并替换引用。
如何解决:

  • 错误方案一:直接给instance1标记为volatile,然后不做任何处理。问题:由于它无法确保原子性,因此创建过程会受其他线程影响,从而导致重复创建。
  • 错误方案二:双重检查锁,问题:拿到未初始化对象。具体见下文:

3、双检查锁失效

首先看一下代码:

publicclassSingleton{privatestaticSingletoninstance2;publicstaticSingletongetInstance2(){if(instance2==null){synchronized(Singleton.class){if(instance2==null){instance2=newSingleton();}}}returninstance2;}}

双检查锁:对象为空时,只让一个线程进去初始化对象。另一个等待线程获取锁后,再次判断是否被初始化,避免重复创建。
为什么能避免重复创建?并发调用getInstance2方法的情况下,后一个线程判断为空之后,还需要等待锁,而那个锁被释放之后。锁内部会再次检查该对象是否被创建,如果已经被创建,则直接跳过对象的创建过程,从而避免再次创建。
问题:只解决了重复创建的问题。还是会出现它被引用,但是没有调用构造方法初始化时。另一个线程通过了非空判断,直接拿到一个未初始化对象的情况。

4、volatile作用

volatile 保证变量的可见性和禁止指令重排序,但不保证原子性。
可见性:写 volatile 会立即刷新到主内存,读 volatile 从主内存读。
重排序:修饰的变量前后插入内存屏障,防止指令重排。
原子性:volatile不能保证i++这类复合操作的原子性,因为读、改、写三步可能被其他线程影响。
因此这里直接利用它的禁止指令重排序的作用,直接修饰单例对象,这样就可以配合synchronized同时保证创建对象过程的原子性、禁止创建过程的指令重排序。

volatileprivatestaticSingletoninstance2;
http://www.jsqmd.com/news/1127326/

相关文章:

  • Beyond Compare 5授权机制深度解析:从加密原理到本地化激活实践
  • 智慧农业实战:基于物联网的自适应智能灌溉系统开发
  • sra_tvm_adapter:鲲鹏TVM适配器完全指南 - 如何为国产处理器优化AI推理性能
  • SQLFlow本地部署全栈包:中文文档+多环境安装脚本+字段级血缘可视化演示
  • 目前短视频评价情况
  • 「 简记往来」第十九篇:Nginx配置与HTTPS证书——让API安全可用
  • 用 Claude Code 一小时重构老项目 CLI 代码实战
  • ANSYS Workbench 12.1中文实操包:从建模、网格到热分析与接触设置的全套学练资源
  • CAPM与Alpha策略实战:Python量化回测中分离Beta风险获取超额收益
  • 跟踪资金流向:使用 ES|QL 和跨集群搜索追踪洗钱网络
  • Java用POI往Word里加文字和图:带全部依赖的即跑示例
  • G-Helper终极指南:如何用轻量级控制工具彻底释放华硕笔记本性能
  • Matlab一键运行TV-Retinex图像增强工具包:含SplitBregman求解器与实操视频
  • NoFuserEx命令行反混淆工具:专为还原NoFuser加壳的.NET程序设计,含dnlib依赖与调试支持文件
  • 微信积分商城小程序源码包,含全套页面逻辑、配置文件与可直接使用的图标资源
  • 空洞骑士模组管理革命:Scarab如何用3分钟改变你的游戏体验?
  • AI大模型系统化学习路线与实践指南
  • 微信天气小程序源码:15天预报+城市搜索+自动切换天气背景图
  • 一站式密码学工具箱ToolsFx:编码、哈希、加密与数字签名实战指南
  • 终极Android VNC客户端指南:AVNC让你轻松远程控制电脑
  • PyTorch 2.0 实战:L1/L2正则化对比,MNIST分类准确率提升 3%
  • Mask R-CNN 实例分割实战:Python + OpenCV 可视化 3 种 Mask 生成流程
  • 跨架构物联网漏洞挖掘:统一IR与动静结合分析实践
  • 本地AI完全指南①:我把ChatGPT退了,一年省2400——为什么越来越多人把大模型搬回家
  • C#版YOLOv8+TensorRT实时检测与ByteTrack多目标追踪工程包(Win10/.NET 4.7.2/VS2019)
  • 热红外视觉下的车辆/船舶重识别新方法:Vc-fes
  • 5分钟上手OpenDesign Templates:vitepress-ts-demo模板使用指南
  • 5G-NR LDPC编译码MATLAB实操包:0.5码率+OMS偏置译码+全程录像指导
  • 前端开发资源合集:47k Star 的学习导航站
  • openeuler/riscv-kernel性能优化指南:提升RISC-V内核性能的实用技巧