单例模式、指令重排序、锁、有序性

今天在回顾单例模式时,我们都知道懒汉式单例中有一种叫做双重检查锁的单例模式。

我们来看下下面的代码有没有问题:
在这里插入图片描述
这段代码我们可以看到,即优化了性能,在多线程情况下,如果实例不为空了,则直接返回了。这样就不用等待排队获取锁了。
同时也保证了线程的安全性,即全程只会出现一个实例。

但是真的没有问题了吗?我们来分析一下:
在执行到 lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();这条语句时,这里是会发生一个指令重排序的问题的。什么是指令重排序呢?
正常的我们创建一个对象,对于底层来说是: a. 内存分配 b. 初始化 c. 返回对象引用

但是由于指令重排序:我们的指令执行过程可能会成为 a. 内存分配 b. 返回对象引用 c. 初始化

如果是我们指令重排序的这种结果。那我们上面的代码就会产生问题了。
即:假设第一个线程执行到了 lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); 这条语句,但是只是执行了指令中的 a 、 b 即初始化还没有完成,但此时 lazyDoubleCheckSingleton这个引用已经不为空了,此时第二个线程过来,在外层判断发现lazyDoubleCheckSingleton不等于空,就直接返回了,但此时返回的对象很明显是个半成品,还没有初始化。因此就会导致产生不可预估的错误。

具体为什么会产生指令重排序,或者指令重排序的详细概念请看https://blog.csdn.net/weixin_37841366/article/details/113086438

以上是问题的背景。

但是我的疑问是为什么会产生指令重排序呢?我印象中学习过的JUC不是说加锁:即Synchronized是可以保证 有序性、可见性、原子性的吗?这个赋值创建的语句这不是在Synchronized代码块里面呢吗?怎么会有指令重排序的问题呢?

下面我们就来分析一下为什么会产生这样的问题吧~

首先我们需要先好好理解一下加锁保证的有序性和volatile关键字防止指令重排序保证的有序性的区别。

首先我们需要明确一点:那就是加锁是无法防止指令重排序的。那为什么说他能够保证有序性呢?

我们需要了解一个语义:

编译器和处理器必须遵守as-if-serial语义,即不管怎么重排序(编译器和处理器为了提高并行度),单线程程序的执行结果不能被改变。

因为Synchronized块中的代码相当于是单线程执行的,而因为这个语义的存在,单线程执行的执行结果是保证不能被改变的,因此Synchronized代码块包裹的代码是有序的代码。这里的有序指的是宏观的有序。

但我们的双检查单例为什么靠Synchronized锁做不到保证有序呢?
因为我们在代码块外面的那个if判断是不受Synchronized控制的。Synchronized的内部是有序了。但是外部依旧无序。

因此上面的代码我们需要添加volatile关键字防止指令重排序。让其保证微观上的强有序性。

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

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

相关文章

[element-ui] el-select,虚拟滚动(vue-virtual-scroll-list)

一、问题描述 表单中某下拉框,由于数据过多,选择的时候会因为数据量过大导致页面卡顿,于是对于el-select进行二次封装,实现虚拟滚动。 二、实现如下: 看起来是加载了全部数据,实际上只加载了自己设定的1…

无需学习Python,一个公式搞定领导想看的大屏

摘要:本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 不要让“做不了”成为数字化转型的障碍 随着数字化的脚步加快,越来越多的企…

Spring Batch之读数据库—JdbcCursorItemReader之自定义PreparedStatementSetter(三十八)

一、自定义PreparedStatementSetter 详情参考我的另一篇博客: Spring Batch之读数据库——JdbcCursorItemReader(三十五)_人……杰的博客-CSDN博客 二、项目实例 1.项目实例 2.代码实现 BatchMain.java: package com.xj.dem…

制作Visual Studio离线安装包

vs2015之后官网就不提供离线安装包了,使用离线安装包就需要自己手动制作一个; 以vs2019为例: 先去官网下载在线安装器 官网下载地址:Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本 (microsoft.com) 展开2019的标签…

从小白到大神之路之学习运维第62天--------Ansible自动化运维工具(playbook配置深入了解2.0)

第三阶段基础 时 间:2023年7月17日 参加人:全班人员 内 容: playbook配置深入了解2.0 目录 一、角色 实验案例:(安装Mariadb) 二、变量 (一)在playbook中使用自定义变量&#xff1…

STM32芯片型号命名规则

意法半导体STM32和STM8系列的芯片可以通过下面一张图来确定芯片的各项参数,帮助选型。 STM32型号的说明:以STM32F103RBT6这个型号的芯片为例,该型号的组成为7个部分,其命名规则如下: ![在这里插入图片描述](https:…

文心一言 VS 讯飞星火 VS chatgpt (61)-- 算法导论6.4 5题

文心一言 VS 讯飞星火 VS chatgpt (61)-- 算法导论6.4 5题 五、证明:在所有元素都不同的情况下,HEAPSORT 的时间复杂度是 Ω (nlgn)。 文心一言: 要证明在所有元素都不同的情况下,HEAPSORT 的时间复杂度是 Ω(n log…

青岛大学_王卓老师【数据结构与算法】Week05_14_队列的顺序表示和实现2_学习笔记

本文是个人学习笔记,素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享, 另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权,请留言作删文处理。 课程视频链接: 数据结构与算法基础…

科研创新服务平台性能分析案例

前言 信息中心老师反应,用户反馈科研创新服务器平台有访问慢的情况,需要通过流量分析系统来了解系统的运行情况,此报告专门针对系统的性能数据做了分析。 信息中心已部署NetInside流量分析系统,使用流量分析系统提供实时和历史原…

走进人工智能|机器人技术 人机协作新纪元

前言: 机器人技术为人类提供协助、增强生产力,改善生活质量,并推动科技进步和社会发展。 文章目录 序言背景核心技术支持人机协作新纪元目前形式领跑人困难和挑战 总结 机器人技术作为现代科技领域的重要研究方向,已经在各个领域展…

TCP/IP网络编程 第十五章:套接字和标准I/O

标准I/O函数的优点 标准I/O函数的两个优点 将标准I/O函数用于数据通信并非难事。但仅掌握函数使用方法并没有太大意义,至少应该 了解这些函数具有的优点。下面列出的是标准I/O函数的两大优点: □标准I/O函数具有良好的移植性(Portability) □标准I/O函数可以利用缓…

LabVIEW将彩色图像转换到灰度图像

LabVIEW将彩色图像转换到灰度图像 在LabVIEW中使用许多图像处理工具的必要步骤之一是将其从彩色转换为单色。介绍一个开发的应用程序,用于基于LabVIEW软件环境,在所有支持的色彩空间(RGB、HSI、HSV和HSL)中自动将彩色图像转换为灰…