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

news2024/11/17 17:24:06

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

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

但是真的没有问题了吗?我们来分析一下:
在执行到 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.coloradmin.cn/o/756898.html

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

相关文章

1766_perl实现readlines功能

全部学习汇总: GreyZhang/perl_basic: some perl basic learning notes. (github.com) 近段时间写一个Perl程序,中间反反复复用到了文件的读写。虽说是用Perl的基本功能实现读写非常简单,但是写的过程中我不止一次在想Python以及MATLAB的功能…

华为OD机试真题 Java 实现【评论转换输出】【2023 B卷 100分】,附详细解题思路

目录 专栏导读一、题目描述在这里插入图片描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A…

什么是元学习?外循环和内循环?支持集和查询集?

一、前言 元学习近几年也算是一个比较热门的研究方向,大部分被用来解决低资源少样本零样本学习的任务场景中。 那么为什么元学习可以提升低资源少样本的学习效果呢?活着说元学习到底是一个什么阳的算法呢? 这里做一个简单的概念阐述。元学…

echart之map地图图表使用教程

本文以echarts展示成都地图为例子。 echarts map (echarts地图)使用教程 效果展示准备阶段获取地图geojson数据安装echarts 开始绘制容器准备js代码 补充事项vue3.0 用ref定义echarts报错toRaw、markRaw 扩展 地图隐藏南海诸岛地图显示提示框地图实现下钻…

Vue项目的启动

前言: 由于最近开始实习,负责人上来就给我丢一个前端vue项目和后端文件,让我在本机完成部署,由于之前学的基本上都是后端相关知识,很少有了解到前端的东西,因此在这里将自己部署Vue项目时遇到的问题和解决过…

编译libtiff库给IOS平台用

打开libtiff官方网 : libtiff / libtiff GitLab 克隆: git clone --recursive https://gitlab.com/libtiff/libtiff.git 克隆成功并打开libtiff目录,发现有autogen.sh 与CMakeLists.txt所以可生成Configure程序来配置并编译,也可直接使用CMake-GUI来配置编译,选择其中一种 …

远程会诊如何实现?

比如:医生遇到复杂病情需要求助院外专家远程会诊过程中,需要将电脑中的病人资料给院外专家看,同时确保医院电脑和网络系统绝对安全,电脑不允许安装任何外部软件,不能被外人控制和操作,外部设备不能接入医院…

【Java技术专题】「攻破技术盲区」带你攻破你很可能存在的Java技术盲点之技术功底指南(鲜为人知的技术)

带你攻破你很可能存在的Java技术盲点之技术功底指南 基本类型的包装类技术盲点:基本类型的比较技术盲点:字符串内部化(string interning)字符串内部化的示例 技术盲点:类型缓存机制(空间换时间)…

微信小程序border-radius不圆滑

border-radius可以设置:百分比或者像素值 1.使用像素值比较圆滑 2.使用百分比不够圆滑

习题1.25

对吗?实践出真知,运行看看。代码如下。 (defn square [x] (* x x))(defn fast-expt[b n](println "call iter" n)(cond (= 1 n) b(= 2 n) (square b)(even? n) (square (fast-expt b (/ n 2))):else (* b (fast-expt b (- n 1)))))(defn expmod [base exp m](mod…

pytest 结合logging输出日志保存至文件

API_log.py import loggingclass loger():def logering(self):# 创建logger对象logger logging.getLogger(test_logger)# 设置日志等级logger.setLevel(logging.DEBUG)# 追加写入文件a ,设置utf-8编码防止中文写入乱码test_log logging.FileHandler(test.log, a,…

Java:基于JDBC数据连接池方式同步第三方数据库表信息数据

前言 最近遇到一个需求就是要拉取第三方的数据信息,但是第三方那边又没有对外暴露对接接口,只给出了具体的数据库连接信息和具体表信息基于第三方给出的有效信息,我采取了用 JDBC 传统的方式去进行数据拉取注意:前置条件两端的网…

收费站对讲广播系统方案

收费站对讲广播系统方案 收费站对讲广播系统是一种用于收费站内部通信和广播传输的系统。它能够实现不同收费站点之间的语音通信和广播,以便快速、准确地传达信息和指令。该系统通常由以下几个核心组件组成:1. 主控台:主控台是系统的中心控制…

cocos shader在编辑器正常,浏览器上不显示

问题出在需要将图片的package属性取消勾选。如果用的单色精灵,那么可以将系统的白色图片复制一份再取消勾选。 相关链接: shader在浏览器上不显示 - Creator 2.x - Cocos中文社区

Redis高级篇(一)

分布式缓存 -- 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: 1.Redis持久化 Redis有两种持久化方案:RDB持久化、AOF持久化 1.1.RDB持久化 什么是RDB持久化 RDB全称Redis Database Backup file(Redis数据备份文件&am…

第一章 JavaScript --下

第一章 JavaScript --下 2.5.6 DOM操作 由于实际开发时基本上都是使用JavaScript的各种框架来操作,而框架中的操作方式和我们现在看到的原生操作完全不同,所以下面罗列的API仅供参考,不做要求。 2.5.6.1 在整个文档范围内查询元素节点 功…

XUbuntu22.04之vim无法复制内容到系统(一百八十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

2023年7月14日,ArrayList

集合框架图: 集合和数组的区别 AarrayList ArrayList底层实现原理 ArrayList的底层实现是基于数组的动态扩容。 初始容量:当创建一个新的ArrayList对象时,它会分配一个初始容量为10的数组。这个初始容量可以根据需求进行调整。 //表示默认的初…

CS162 9-10

lecture9 thread lecture10 I/O层 调度 1.最小化响应时间 2.最大化吞吐量 3.分配时间公平 FCFS 后面的短请求,要等待前面的长请求。 Round Robin Scheduling Each process gets a small unit of CPU time (time quantum), usually 10-100 milliseconds – …

layui会议OA项目数据表格新增改查

文章目录 前言一、后台代码编写1.1 数据表优化1.2 R工具类1.3 UserDao新增改查1.4 Servlet的编写 二、前台页面的编写2.1 userManege.jsp2.2 userManage.js2.3 新增、修改用户共用jsp2.4add、edit的js 三、演示3.1 查询3.2 新增3.3 修改3.4 删除 前言 在上篇博客我们实现了左侧…