【揭秘】单例模式DCL导致无法访问对象?

【揭秘】单例模式DCL导致无法访问对象? - 程序员古德

前两天,在审查团队成员的代码时,我发现了一个错误的单例模式写法。

在Java中,单例模式是一种非常常见的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例,但是,如果不正确地实现单例模式,就可能导致多个实例被创建,从而违反了单例模式的初衷。

如下,是你说的有问题的代码,即未使用volatile关键字的DCL单例模式实现:

public class Singleton {  private static Singleton instance;  private Singleton() {}  public static Singleton getInstance() {  if (instance == null) { // 第一次检查  synchronized (Singleton.class) {  if (instance == null) { // 第二次检查  instance = new Singleton(); // 创建实例  }  }  }  return instance;  }  
}

在这个有问题的代码中,instance = new Singleton(); 这行代码实际上包含三个步骤:

  1. 分配内存给 Singleton 对象
  2. 调用 Singleton 的构造函数初始化对象。
  3. instance 字段指向新创建的对象。

在没有 volatile 关键字的情况下,由于指令重排序,步骤2和步骤3的顺序可能会被颠倒,这意味着,当其他线程看到 instance 不为null时(即步骤3已经完成),它可能会访问这个对象,但此时对象可能还没有被完全初始化(即步骤2还没有完成),这就你所说的“未初始化完全的实例对象”的问题。

为了避免这个问题,我们需要确保步骤2和步骤3之间的顺序不会被颠倒,即确保在使用双重检查锁定(DCL)实现单例模式时对象能够完全初始化并且不会被多个线程同时初始化,这就是为什么我们需要在 instance 字段上添加 volatile 关键字的原因,volatile 关键字能够确保变量的可见性和有序性,且保证变量的读写操作都是原子的和禁止指令重排序,从而保证了对象的完全初始化。

下面是使用volatile关键字修复后的DCL单例模式实现:

public class Singleton {  private static volatile Singleton instance; // 声明为volatile,确保线程安全  private Singleton() {} // 私有构造函数,防止外部实例化  public static Singleton getInstance() {  if (instance == null) { // 第一次检查,如果为null才进入同步块  synchronized (Singleton.class) {  if (instance == null) { // 第二次检查,如果为null才创建实例  instance = new Singleton(); // 创建实例对象  }  }  }  return instance; // 返回单例实例  }  
}

在这个修复后的实现中,当第一个线程执行到 instance = new Singleton(); 时,由于 instancevolatile 的,它会保证以下三件步骤按照顺序发生:

  1. 分配内存给 Singleton 对象。
  2. 调用 Singleton 的构造函数,完全初始化对象。
  3. instance 字段指向新创建的对象。

并且,由于 volatile 的内存屏障效应,这个初始化过程对其他线程是可见的,也就是说,其他线程在看到这个 instance 不为 null 时,能够保证它已经被完全初始化了,这样就避免了之前提到的“未初始化完全的实例对象”的问题。

该问题所涉及的核心知识点参考:

Java内存模型(JMM):JMM定义了线程和主内存之间的交互方式,每个线程都有自己的工作内存,线程之间共享主内存,同时,JMM规定了一些规则,确保变量的值在线程之间正确同步。

指令重排序:编译器和处理器可能会对指令进行重排序,只要这种重排序在单线程环境下不改变程序的执行结果,它就是可接受的,然而,在多线程环境下,这种重排序可能导致问题

完!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/598514.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue项目报错RangeError: Maximum call stack size exceeded

我的代码–> <script> import groupSettings from ./groupSetting.vue export default {name: groupSettings,components: {groupSettings}, </script>答应我&#xff0c;你的子组件引入名称一定不能和name一样&#xff01;&#xff01;&#xff01;

运算放大器(六):I-V 转换

1、跨阻放大器 放大器类型是根据其输入-输出信号的类型定义。假设放大器增益 &#xff08;X&#xff1a;输入&#xff0c;Y&#xff1a;输出&#xff09;。在电学范畴&#xff0c;由于用电压或电流表征一个信号&#xff0c;当输入信号为电流&#xff0c;输出信号为电压时&#…

数字孪生在虚拟现实(VR)中的应用

数字孪生在虚拟现实&#xff08;VR&#xff09;中的应用为用户提供了更深入、沉浸式的体验&#xff0c;同时通过数字孪生技术模拟真实世界的物理实体。以下是数字孪生在VR中的一些应用&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发…

mariadb配置慢sql查询

Mariadb和Mysql配置相同 这里配置的事mariadb 修改配置文件 vi /etc/my.cnf.d/server.cnf[mysqld] slow_query_logon slow_query_log_file/data/mysql_data/slow_query_log.log long_query_time2slow_query_logon 开启慢sql查询slow_query_log_file/data/mysql_data/slow_que…

kubectl 源码分析

Cobra库 k8s各组件的cli部分都使用Cobra库实现&#xff0c;Cobra 中文文档 - 掘金 (juejin.cn)&#xff0c;获取方式如下&#xff1a; go get -u github.com/spf13/cobralatest cobra库中的Command结构体的字段&#xff0c;用于定义命令行工具的行为和选项。它们的作用如下&…

56K star!一键拥有跨平台 ChatGPT 应用:ChatGPT-Next-Web

前言 现在围绕 openai 的客户端层出不穷&#xff0c;各路开发大神可以说是各出绝招&#xff0c;我也试用过几个国内外的不同客户端。 今天我们推荐的开源项目是目前我用过最好的ChatGPT应用&#xff0c;在GitHub超过56K Star的开源项目&#xff1a;ChatGPT-Next-Web。 ChatGP…

一创聚宽停止服务,散户可以选择它!

第一创业和聚宽停止合作&#xff01;还有什么量化平台可选&#xff1f; 先了解背景&#xff1a; 从2023年9月25日起&#xff0c;一创聚宽的量化交易平台暂停开通交易权限&#xff0c;到2023年12月29日&#xff0c;一创聚宽量化交易平台将停止提供所有服务。这一消息对于之前使…

Python基础入门第七课笔记(自定义函数 define)

函数 函数必须先定义再调用 函数必须先定义再调用 函数必须先定义再调用 定义函数&#xff1a; def 函数名&#xff08;形参&#xff09;&#xff1a; 代码1 代码2 ………. 调用函数&#xff1a; 函数名&#xff08;实参&#xff09; 形参&…

Spring MVC响应结合RESTful风格开发,打造具有强大功能和良好体验的Web应用!

响应与Rest风格 1.11.1.1 环境准备步骤1:设置返回页面步骤2:启动程序测试 1.1.2 返回文本数据步骤1:设置返回文本内容步骤2:启动程序测试 1.1.3 响应JSON数据响应POJO对象响应POJO集合对象 知识点1&#xff1a;ResponseBody 2&#xff0c;Rest风格2.1 REST简介2.2 RESTful入门案…

技术概述:ARMv8体系结构

John Goodacre, Director Program Management ARM Processor Division, November 2011 背景&#xff1a;ARM体系结构 从ARM精简指令集体系结构提出到现在已经有20多年了&#xff1b;ARMv7系列处理器是在ARMv4基础上设计的&#xff0c;随着ARMv7系列处理器大量应用&#xff0…

争做智驾“第一阵营”,锚定“全球前五”,小米汽车底气何在?

“官宣”造车超1000天后&#xff0c;低调行事的小米终于进行了首次“军火展示”。 2023年12月28日&#xff0c;小米集团&#xff08;HK:01810&#xff0c;下称“小米”&#xff09;在北京举办小米汽车技术发布会&#xff0c;公布了小米汽车核心技术及首款产品小米SU7。按照规划…

对话新七天创始人&CEO左英杰:品牌直播电商出圈“五步法”

整理 | 飞族 编辑 | 渔舟 出品&#xff5c;极新&#xff06;北京电子商务协会 AI、AIGC、VR等数智化新技术发展日新月异&#xff0c;在直播电商领域的应用和探索逐渐深入&#xff0c;从内容生成、创意优化、购物体验、智能客服、精准营销等方面提供全方位全链路的赋能&#…

用C语言采集游戏平台数据并做行业分析

目录 一、数据采集方法 日志采集 API采集 二、数据采集流程 确定采集目标 选择采集方法 编写采集程序 数据清洗和整理 三、行业分析方法 对比分析 趋势分析 分类分析 四、案例分析&#xff1a;基于C语言的实时游戏平台数据采集与行业分析系统实现 五、结论 随着游…

windows 10 安装wsl ubuntu

1.首先管理员模式打卡powershell&#xff0c;执行 dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart 2.执行 wsl --update wsl --…

python 基础语法函数

函数定义 def 函数名(形参列表用逗号隔开)&#xff1a; 函数体 return 返回值 # 有参数 无返回值 def my_length(data):count 0for i in data:count 1print(f"data count{count}")my_length(str1) my_length(str2)#无参数无返回值 def say_hello():print("h…

全网唯一值得推荐的C/C++框架和库

全网唯一值得推荐的C/C框架和库 C程序员开发指南 ​ 关注我&#xff0c;天天分享C/C开发技术干货&#xff01; ​关注他 30 人赞同了该文章 ​ 目录 收起 标准库 C通用框架和库 人工智能 异步事件循环 音频 生态学 压缩 并发性 容器 数据库 调试 游戏引擎 图…

西门子消防主机控制面板显示盘维修B3Q565

作为图形监控主机&#xff0c;负责接收并储存各消防设备主要运行状态&#xff0c;接收火灾报警并显示报警部位&#xff0c;包括火灾报警、状态监视、设备故障报警、网络故障报警﹐指挥抢险救援的活动,进行火灾信息的处理与传送&#xff0c;同时具备提示操作人员的功能&#xff…

TS:类型断言

类型断言好比其他语言中的类型转换&#xff0c;但是不是真正的类型转换方式&#xff0c;之所以不被称为类型转换&#xff0c;是因为转换通常意味着某种运行时的支持。但是&#xff0c;类型断言纯粹是一个编译时语法&#xff0c;同时&#xff0c;它也是一种为编译器提供关于如何…

使用代理IP实现爬虫的匿名性

目录 前言 一、什么是代理IP&#xff1f; 二、使用Python实现代理IP爬虫 1. 安装所需模块 2. 获取代理IP列表 3. 使用代理IP进行爬取 4. 使用代理IP进行数据抓取 三、总结 前言 随着互联网的快速发展&#xff0c;网络爬虫已经成为了获取互联网数据的一种重要方式。然而…

原生JS实现抽奖

1、效果展示 0. 制作一个MiniSize使用提供的素材实现一个转盘活动的布局&#xff08;如下图所示&#xff09;&#xff1b; 进入界面后2秒钟后开始旋转&#xff0c;5秒钟后停止旋转&#xff1b;并且3秒后进入一个表单界面&#xff08;如下图2所示&#xff09;&#xff1b;界面…