内存可见性
内存可见性
- 一:内存可见性
- 1.2:
- 二:解决内存可见性问题
- 2.1 volatile关键字
- 2.2:synchronized关键字解决内存可见性问题
一:内存可见性
public class Demo1 {public static int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(()->{while(count==0){}System.out.println("t1线程结束");});Thread t2=new Thread(()->{Scanner scanner=new Scanner(System.in);1System.out.println("请输入一个整数:");count=scanner.nextInt();});t1.start();t2.start();}
}
上述代码预期效果:
t1线程首先进入循环,当用户输入一个非0整数的时候,就会使t1线程退出循环.结束线程.
但t1实际上并没有真正出现退出的情况,这也是"bug",而产生上述现象的原因,就是**“内存可见性”**
while(count==0){}
从指令角度分析这段代码:
(1)load :从内存读取数据到CPU 寄存器中,
(2)cmp:比较,条件成立,继续循环,条件不成立,退出循环.
然而,一个load指令消耗的时间,会比一个cmp指令消耗的时间多得多,执行一次load的时间,等于上万次cmp执行消耗的时间.
同时,JVM发现每次load执行的结果,是一样的(t2线程修改之前),因此,**JVM就把上述load操作优化掉了,只是第一次真正进行load,后续再执行到load,而是直接读取已经load过的寄存器中的值了(读取寄存器的速度远远大于 读取内存的速度).**当t2线程修改count的值,但由于t1线程并没有从内存中重新读取,所以获取不到更新后的值.
1.2:
public class Demo1 {public static int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(()->{while(count==0){System.out.println("hello ");}System.out.println("t1线程结束");});Thread t2=new Thread(()->{Scanner scanner=new Scanner(System.in);System.out.println("请输入一个整数:");count=scanner.nextInt();});t1.start();t2.start();}
}
当我们在
while(count==0){System.out.println("hello ");}
while循环中打印,就会发现代码又和我们预期的效果一样了,这又是为什么???
因为循环体内存在IO操作,而IO操作是从硬盘中获取数据,因此IO操作消耗的时间比load操作消耗的时间更多,并且IO操作是不能被优化掉的.
总结:上述问题本质上是编译器优化引起的(优化是由javac和java配合完成的工作),优化掉load操作之后,使t2线程的修改,没有被t1线程感知到,这就造成了"内存可见性"问题
二:解决内存可见性问题
2.1 volatile关键字
编译器什么时候优化,什么时候不优化,这是一个"玄学问题".
通过volatile关键字,解决优化问题,让编译器不再优化.
当给变量修饰上volatile关键字之后,编译器就知道了,这个变量是"反复无常"的,编译器就不会再进行优化了
volatile 是专门针对内存可见性的场景来解决问题的,告诉编译器不要进行优化操作.
public class Demo1 {public volatile static int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(()->{while(count==0){}System.out.println("t1线程结束");});Thread t2=new Thread(()->{Scanner scanner=new Scanner(System.in);System.out.println("请输入一个整数:");count=scanner.nextInt();});t1.start();t2.start();}
}
2.2:synchronized关键字解决内存可见性问题
synchronized关键字,和volatile关键字处理逻辑上是不同的.
引入synchronized关键字,是因为加锁操作本身太重量了,相比load 来说,开销更大,编译器自然就不会对load 优化了(和sleep ,IO操作原理类似).
public class Demo1 {public static int count = 0;public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread t1=new Thread(()->{while(count==0){synchronized (locker){{}}}System.out.println("t1线程结束");});Thread t2=new Thread(()->{Scanner scanner=new Scanner(System.in);System.out.println("请输入一个整数:");count=scanner.nextInt();});t1.start();t2.start();}
}
相关文章:
内存可见性
内存可见性 一:内存可见性1.2: 二:解决内存可见性问题2.1 volatile关键字2.2:synchronized关键字解决内存可见性问题 一:内存可见性 public class Demo1 {public static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1new Thre…...
Android room 在dao中不能使用挂起suspend 否则会报错
错误: Type of the parameter must be a class annotated with Entity or a collection/array of it. kotlin.coroutines.Continuation<? super kotlin.Unit> $completion); 首先大家检查一下几个点 一、kotlin-kapt 二、 是否引入了 room-ktx 我是2024年…...
【stable diffusion扩散模型】一篇文章讲透
目录 一、引言 二、Stable Diffusion的基本原理 1 扩散模型 2 Stable Diffusion模型架构 3 训练过程与算法细节 三、Stable Diffusion的应用领域 1 图像生成与艺术创作 2 图像补全与修复 3 其他领域 四、Stable Diffusion的优势与挑战 👉优势 …...
数据链路层之信道:数字通信的桥梁与守护者
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...
SQL109 纠错4(组合查询,order by..)
SELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_state MI UNION SELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_state IL ORDER BY cust_name;order by子句,必须位于最后一条select语句之后...
Spring Boot + Vue 实现文件导入导出功能
文章目录 1、概述2、后端实现(Spring Boot)3、前端实现(Vue)4、总结 1、概述 在现代Web应用开发中,文件的导入导出是一个常见的需求。Spring Boot作为后端开发的强大框架,搭配前端框架Vue,可…...
vue watch 深度监听
vue2文档:API — Vue.js vue3文档:侦听器 | Vue.js watch 可以用来监听页面中的数据,但如果监听的源是对象或数组,则使用深度监听,强制深度遍历源,以便在深度变更时触发回调。 一,监听 <t…...
Qt源码调试步骤记录
1.源码: 两种方式,要么安装qt时选择source,要么从官网下载源码,然后在qt creator中设置路径。二选一即可。我选的第二种。 1.1.第一种,安装时选择source: 1.2.第二种,下载源码设置路径&#x…...
大数据面试英文自我介绍参考(万字长文)
发现有一个怪圈,如果码农年龄35+,除非非常匹配,不然在国内企业筛选可能就筛选不过。国外码农可以干到40+、50+。一些外企,对年龄35+的码农依然青睐。这些外企对英文是有要求,通常是要英文自我介绍,下面提供一些英文自我介绍参考。 参考1: Good morning/afternoon, I a…...
外包干了5天,技术退步明显.......
先说一下自己的情况,大专生,18年通过校招进入杭州某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…...
Docket常见的软件部署1
1 安装MySQL # 查看MySQL镜像 docker search mysql # 拉起镜像 docker pull mysql:5.7 # 创建MySQL数据映射卷,防止数据不丢失 mkdir -p /hmoe/tem/docker/mysql/data/ # 启动镜像 docker run -d --name mysql -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -v /home…...
Qt源程序编译及错误问题解决
Error 5 while parsing C:/qt-everywhere-src-6.6.2/qt-build/qtdeclarative/src/qmlmodels/meta_types/qt6qmlmodels_release_metatypes.json: illegal value .json 文件为空文件0字节,加 “[]”,不要引号。可以解决这类错误。 Qt编译 Qt for Windows…...
作业练习(python)
第一题: cel eval(input()) fah 9 / 5 * cel 32 print("%.1f" % fah) 第二题: radius, length eval(input()) area radius * radius * 3.14159267 volume area * length print("%.2f" % area) print("%.2f" …...
Wireshark使用相关
1.wireshark如何查看RST包 tcp.flags.reset1 RST表示复位,用来异常的关闭连接,在TCP的设计中它是不可或缺的。发送RST包关闭连接时,不必等缓冲区的包都发出去(不像上面的FIN包),直接就丢弃缓存区的包发送R…...
相机标定学习记录
相机标定是计算机视觉和机器视觉领域中的一项基本技术,它的主要目的是通过获取相机的内部参数(内参)和外部参数(外参),以及镜头畸变参数,建立起现实世界中的点与相机成像平面上对应像素点之间准…...
CSS 滚动条样式修改
1、滚动条整体部分 使用 ::-webkit-scrollbar 注意:这个必须要加,不然修改的样式不生效 ::-webkit-scrollbar {width: 10px;//修改滚动条宽度 }2、滚动条中的滑块 使用 ::-webkit-scrollbar-thumb ::-webkit-scrollbar-thumb {border-radius: 8px;b…...
谈谈配置中心?
配置中心可以做集中式的服务配置管理,比如配置一些数据库连接的URL,一些共用的配置且可动态调整的参数。如果不采用集中式的管理,会导致修改起来特别麻烦,一个个的修改特别繁琐。 Nacos Config配置中心中采用的是客户端拉取数据&a…...
人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景,模型结构介绍
大家好,我是微学AI,今天给大家介绍一下人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景,模型结构介绍。特征金字塔网络(FPN)是一种深度学习模型结构,主要应用于目标检测任务中&am…...
JRT业务开发起步
这是一段充满挑战与奋斗的旅程,自第一行Java代码的写下起,便历经重重险阻。从细微的代码行,逐步汇聚成实用的工具类方法;从工具类方法的积累,逐渐构建起功能强大的工具包;再从工具包的整合,最终…...
深度解析:国内主流音视频产品的核心功能与市场表现
前言 当前音视频开发领域呈现出多样化竞争态势,其中声网(Agora)、即构(ZEGO)等云通讯企业占据了市场的主导地位。随着技术的持续进步和用户需求的日益多样化,选择音视频服务提供商的标准也越来越个性化&am…...
红黑树介绍及插入操作的实现
🎉个人名片: 🐼作者简介:一名乐于分享在学习道路上收获的大二在校生 🙈个人主页🎉:GOTXX 🐼个人WeChat:ILXOXVJE 🐼本文由GOTXX原创,首发CSDN&…...
[linux初阶][vim-gcc-gdb] TwoCharter: gcc编译器
目录 一.Linux中gcc编译器的下载与安装 二.使用gcc编译器来翻译 C语言程序 ①.编写C语言代码 ②翻译C语言代码 a.预处理 b.编译 c.汇编 d.链接 ③.执行Main 二进制可执行程序(.exe文件) 三.总结 一.Linux中gcc编译器的下载与安装 使用yum命令(相当于手机上的应用…...
单例设计模式(2)
单例设计模式(2) 单例模式存在的问题 单例对 OOP 特性的支持不友好 oop的特性:封装、继承、多态、抽象;以Id生成器代码为例,如果未来某一天,我们希望针对不同的业务采用不同的 ID 生成算法。比如&#x…...
boost::asio 启用 io_uring(Linux 5.10)队列支持
欲启用 boost::asio 对于 io_uring 的支持,这需要以下几个先决条件; 1、boost 1.78 及以上发行版本 Revision History - 1.78.0 (boost.org) 2、Linux kernel 5.10 及以上发行版本 3、在预定义头文件(stdafx.h)、或编译器预定义…...
Android 自定义坐标曲线图(二)
Android 自定义坐标曲线图_android 自定义曲线图-CSDN博客 继上一篇文章,点击折线图上的点,显示提示信息进行修改,之前通过回调,调用外部方法,使用popupwindow或dialog来显示,但是这种方法对于弹框显示的位…...
每日OJ题_子序列dp⑧_力扣446. 等差数列划分 II - 子序列
目录 力扣446. 等差数列划分 II - 子序列 解析代码 力扣446. 等差数列划分 II - 子序列 446. 等差数列划分 II - 子序列 难度 困难 给你一个整数数组 nums ,返回 nums 中所有 等差子序列 的数目。 如果一个序列中 至少有三个元素 ,并且任意两个相邻…...
GOPROXY 代理设置
通常报错: 1.http: server gave HTTP response to HTTPS client 2.timeout 解决指令:(会话临时性),长久的可以在配置文件中配置 go env -w GOPROXYhttps://goproxy.cn,direct 长久的,在~/.bashrc文件中添加: expo…...
Redis面经
Redis面经 Redis缓存穿透、缓存击穿和缓存雪崩及解决方案概述缓存穿透详解及解决方案缓存击穿详解及解决方案缓存雪崩详解及解决方案 Redis持久化机制什么是数据持久化?Redis数据持久化概述RDB持久化的优缺点AOF持久化混合持久化 Redis缓存穿透、缓存击穿和缓存雪崩…...
【c++】类和对象(六)深入了解隐式类型转换
🔥个人主页:Quitecoder 🔥专栏:c笔记仓 朋友们大家好,本篇文章我们来到初始化列表,隐式类型转换以及explicit的内容 目录 1.初始化列表1.1构造函数体赋值1.2初始化列表1.2.1隐式类型转换与复制初始化 1.3e…...
什么是nginx正向代理和反向代理?
什么是代理? 代理(Proxy), 简单理解就是自己做不了的事情或实现不了的功能,委托别人去做。 什么是正向代理? 在nginx中,正向代理指委托者是客户端,即被代理的对象是客户端 在这幅图中,由于左边内网中…...
免备案空间网站/地方网站建设
首先在oracle中没有datediff()函数可以用以下方法在oracle中实现该函数的功能:1.利用日期间的加减运算天:ROUND(TO_NUMBER(END_DATE - START_DATE))小时:ROUND(TO_NUMBER(END_DATE - START_DATE) * 24)分钟:ROUND(TO_NUMBER(END_DATE - START…...
股票交易网站建设/网络产品及其推广方法
让我们来看一下与数字签名并行的一个有用技巧,基本想法是从数字签名模式中拿出一个公共验证密钥,并将其与一个 人或一个系统参与者的身份对等。如果你见到一条消息的签名被公钥pk正确验证,那么你可以认为pk就是在表达这条消息。你真的可以将公…...
用wordpress好吗/黑龙江头条今日新闻
欢迎您戳蓝色字“工数平台”持续关注我们哟!导言在当今中国的各个领域,“弯道超车”是个经常被提及的口号,然而常识和交规告诉我们,弯道不仅不能超车还得减速,超车极其危险。仔细解读“弯道超车”,其实还暗…...
一般做外单的有哪些网站/315影视行业
1. 卷积神经网络结构 卷积神经网络是一个多层的神经网络,每层都是一个变换(映射),常用卷积convention变换和pooling池化变换,每种变换都是对输入数据的一种处理,是输入特征的另一种特征表达;每层…...
内容网站管理系统/seo排名优化怎样
1. 最简单的方法是用base64:import base64 s1 base64.encodestring(hello world) s2 base64.decodestring(s1) print s1,s2 # aGVsbG8gd29ybGQ\n # hello worldNote: 这是最简单的方法了,但是不够保险,因为如果别人拿到你的密文,也可以自己…...
做网站有什么不好/crm管理系统
方法 转载于:https://www.cnblogs.com/sen068/p/5362695.html...