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

news2024/11/21 2:25:06

【揭秘】单例模式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.coloradmin.cn/o/1358206.html

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

相关文章

微信怎么做小程序店铺?如何制作微信小程序店铺

在这个数字化的时代,拥有一个属于自己的线上店铺已经成为了一种趋势。而微信小程序,作为微信平台上的一种轻应用,无疑成为了许多人开店的首选。那么,如何利用微信小程序开设自己的店铺呢?下面就让我来为大家详细解析一…

盘点2023年12月Sui生态发展,了解Sui近期成长历程!

12月是一年的“收官”月,我们告别了2023,迎来了崭新的2024,而Web3行业多项指标也持续展现增长趋势。Sui紧随行业脚步,开展了一系列生态活动。其中专为圣诞准备的冬季任务送出了50万SUI,与韩国游戏公司NHN合作的NFT限量…

原来圣诞树可以这么做

先看结果 从上到下依次是: 2^0 2^1 2^2 2^3 2^4 2^5 2^6 2^7 ... 依次排下去,最后加4个单位数的数字 原来代码的世界里还有这个美。^V^

软考报名有哪些要求?

报考任何级别不需要学历、资历条件,只要达到相应的专业技术水平就可以报考相应的级别 (一)2024年软考报名入口 2024年软考采用网络报名方式,考生在报名期间进入中国计算机技术职业资格网 (中国计算机技术职业资格网),点击页面右下角的报名入…

飞凌嵌入式2023年度盘点——步履不停,向上而行

刚刚过去的一年充满了挑战 但飞凌嵌入式始终带着对未来的期许 坚定地向上而行 凡是过往,皆为序章 让我们站在2024年的开端 一起回顾飞凌嵌入式的2023年度大事 1、企业实力,稳步提升 2023年,飞凌嵌入式成为国家级专精特新“小巨人”企业…

ZkSync第一Dex空投交互全教程,Holdstation ZK热点不容错过

2023 年 12 月 8 日,在以太坊基金会的 176 次会议上,开发人员一致同意,如果事情进展顺利,将在 2024 年初定 Goerli 分叉日期,目标是能在 2024 年 1 月激活 Goerli Dencun 测试网,预计能够在 2024 年 3 月~ …

Scikit-Learn线性回归(五)

Scikit-Learn线性回归五:岭回归与Lasso回归 1、误差与模型复杂度2、正则化3、Scikit-Learn岭(Ridge)回归4、Scikit-Learn Lasso回归 1、误差与模型复杂度 在第二篇文章 Scikit-Learn线性回归(二) 中,我们已经给出了过拟合与模型泛…

CentOS 7 基于官方源码和openssl制作openssh 9.6 rpm包(含ssh-copy-id) —— 筑梦之路

之前写了一篇: CentOS 7 制作openssh 9.6 rpm包更新修复安全漏洞 —— 筑梦之路_升级openssh9.6-CSDN博客 有好几个网友反馈,ssh-keygen生成密钥存在问题,之前的rsa \ dsa加密算法用不了,因此写了一篇: 关于openssh…

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…

基于MyCat2.0实现MySQL分库分表方案

目录 一、MyCat概述 二、MyCat作用 2.1 数据分片 2.1.1 垂直拆分 2.1.1.1 垂直分库 2.1.1.2 垂直分表 2.1.1.3 总结 2.1.2 水平拆分 2.1.2.1 水平分库 2.1.2.2 水平分表 2.1.2.3 总结 2.2 读写分离 2.3 多数据源整合 三、MyCat 与ShardingJDBC的区别 3.1 MyCat …

vins 实机测试 rs_d435 + imu

vins 实机测试 文章目录 1. imu标定2. camera内参标定3. imu-cam 外参标定4. vins 实际运行5. realsense 1. imu标定 git clone https://github.com/gaowenliang/code_utils.git git clone https://github.com/gaowenliang/imu_utils.git编译运行, roslaunch imu_…

echarts 切换时出现上一次图形残留。

先说结果:悬浮高亮导致。这可能使echarts的bug。 正常情况出现这种问题,一般是setOption 中没有配置notMerge 导致新的配置与旧配置合并。 但是我这里始终配置notMerge: true,但仍然出现这种问题。 最后发现与鼠标悬浮有关。 环境 echar…

小梅哥Xilinx FPGA学习笔记20——无源蜂鸣器驱动设计与验证(音乐发生器设计)

目录 一:章节导读 二:无源蜂鸣器驱动原理 三:PWM 发生器模块设计 3.1 PWM 发生器模块框图 3.2 PWM 发生器模块接口功能描述 3.3 PWM波生成设计文件代码 3.4 测试仿真文件 3.5 测试仿真结果 3.6 板级调试与验证之顶层文件设计 四&am…

民营体检@2023/24:革新、挑战与本质回归

【潮汐商业评论/原创】 被“健康焦虑”困扰的Joy决定给自己来一次全身的检查,在网上一搜才发现,不仅是体检机构,现在各大医院也都可以体检。“感觉价格也都差不多,是选公立还是体检机构呢?”Joy陷入疑惑。 随着近几年…

洛谷 P1873 砍树 (二分 简单)

【二分答案】是分治的一种,这类问题很经典,接下来几篇文章会关于二分答案相关的文章,希望同学们可以完成10道以上的【二分答案】相关问题,以此来加深对【二分答案】这类问题的个人理解。 原公众号链接:分治第二讲&…

pygame学习(二)——绘制线条、圆、矩形等图案

导语 pygame是一个跨平台Python库(pygame news),专门用来开发游戏。pygame主要为开发、设计2D电子游戏而生,提供图像模块(image)、声音模块(mixer)、输入/输出(鼠标、键盘、显示屏)模…

stable diffusion 基础教程-提示词之光的用法

基图 prompt: masterpiece,best quality,1girl,solo,looking at viewer,brown hair,hair between eyes,bangs,very long hair,red eyes,blush,bare shoulders,(white sundress),full body,Negative prompt: EasyNegative,badhandv4,nsfw,lowres,bad anatomy,bad hands,text…

Linux第14步_安装FTP服务器

安装“vim编辑器”后,我们紧接着“安装FTP服务器”。 1、在安装前,要检查虚拟机可以上网,否则可能会导致安装失败。 2、在虚拟机界面右击鼠标,弹出下面的对话框 3、点击“打开终端(E)”,得到下面的界面 :…

YOLOv7独家原创改进:新颖的Shape IoU结合 Inner-IoU,基于辅助边框的IoU损失的同时关注边界框本身的形状和尺度,小目标实现高效涨点

💡💡💡本文改进:一种新的Shape IoU方法结合 Inner-IoU,基于辅助边框的IoU损失的同时,更加关注边界框本身的形状和尺度来计算损失 💡💡💡对小目标检测涨点明显,在VisDrone2019、PASCAL VOC均有涨点 💡💡💡本文改进:一种新的Shape IoU方法,该方法可以通过…

使用“反向代理服务器”的优点是什么?

反向代理服务器是一种网络架构模式,通常位于客户端和实际服务器之间,用于处理客户端请求并转发到实际服务器。以下是使用反向代理服务器的优点: 1.安全性:反向代理服务器可以提供额外的安全层。通过在反向代理服务器上配置防火墙和…