线程不安全情况之内存可见性——volatile

news2025/1/11 17:09:23

内存可见性

影响线程安全的原因有很多,内存可见性的也会引起线程不安全。
以下面的案例来看,线程启动后,t1不断进行循环,直到t2输入数字后改变状态,t1线程才会结束。

	private static int count;
    public static void main(String[] args) {
        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:");
            count = scanner.nextInt();
            System.out.println("count = "+count);
        });
        t1.start();
        t2.start();

    }

通过下面的打印我们可以知道,线程t1并没有执行结束,仍然处于while循环中。那么为什么count值改变了,结果却没有发生改变。这就涉及到了内存可见性的问题。
在这里插入图片描述

内存可见性原因

在上面的代码中,由于循环体中没有内容,线程t1的while循环中需要执行两个操作。

第一个是load操作,即从内存中读取count数据到cpu寄存器中;
第二个是compare操作,即进行count==0的判断操作。如果条件成立,则会顺序执行,条件不成立,就会跳出while循环执行后续代码。

前置条件: 这段循环体中不存在代码,只能反复执行load和compare操作。
1)在循环操作过程中load比compare指令所花费的时间多上许多,一次load操作所花费的时间足够compare执行成千上万次。
2)在JVM中发现load操作每次执行的结果都是相同的(在线程t2修改count值之前已经经过许多次load了)
优化操作: 在发现这样的操作十分的无效以后,JVM开始了他的优化操作:在第一次真正执行了load操作以后,JVM后续继续执行后面的代码以后都不进行load操作了,而是直接读取一开始的load值。
后果: 经过JVM的优化操作,后续的count值即使修改了也无法更新,这也就导致了while循环无法结束。

volatile

为了防止JVM的自作聪明引起的祸端,于是创建了volatile关键字,即反复无常。提醒JVM不可以对带有这个关键字的变量进行优化。

private volatile static int count;

对count变量添加volatile以后,再执行代码,我们可以成功修改count值并更新到while循环中。
在这里插入图片描述

IO操作

在线程t1中,因为while循环中没有语句,最后导致了load操作被优化。如果我们在while循环中添加了打印语句,load操作是否还会被优化?
结果:在执行了下面的代码以后,修改count值是可以停止while循环的。
**原因:**我们知道,load操作是因为过程浪费资源且没有改变才会被优化,而在while循环中,打印的IO操作所耗费的资源比load操作要多得多,并且每次的IO操作所带来的结果是不相同的,于是就形成了 “load操作浪费,但IO操作所花费的资源更多” 。因此load操作没有被优化。

    private volatile static int count;
    public static void main(String[] args) {
        Thread t1 = new Thread(()-> {
            while (count == 0) {
                System.out.println("t1");
            }
            System.out.println("t1执行结束");
        });
        Thread t2 = new Thread(()-> {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入count:");
            count = scanner.nextInt();
            System.out.println("count = "+count);
        });
        t1.start();
        t2.start();
    }

总结

volatile关键字的出现是专门针对内存可见性的场景来解决问题的,并不能解决多线程中多个线程修改同一变量的问题。虽然使用加锁操作也可以在一定程度上解决内存可见性的问题,但加锁所耗费的资源比volatile多得多。
源码☞内存可见性源码

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

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

相关文章

区间动态规划——最长回文子序列长度(C++)

把夜熬成粥,然后喝了它。 ——2024年7月1日 书接上回:区间动态规划——最长回文子串(C)-CSDN博客,大家有想到解决办法吗? 题目描述 给定一个字符串s(s仅由数字和英文大小写字母组成&#xff0…

JavaSEJava8 时间日期API + 使用心得

文章目录 1. LocalDate2. LocalTime3. LocalDateTime3.1创建 LocalDateTime3.2 LocalDateTime获取方法 4. LocalDateTime转换方法4.1 LocalDateTime增加或者减少时间的方法4.2 LocalDateTime修改方法 5. Period6. Duration7. 格式转换7.1 时间日期转换为字符串7.2 字符串转换为…

基于YOLOv5的人脸目标检测

本文是在之前的基于yolov5的人脸关键点检测项目上扩展来的。因为人脸目标检测的效果将直接影响到人脸关键点检测的效果,因此本文主要讲解利用yolov5训练人脸目标检测(关键点检测可以看我人脸关键点检测文章) 基于yolov5的人脸关键点检测:人脸关键点检测…

FL Studio 21.0.3.3517中文破解版2024最新Keygen免费下载安装激活教程

你们是否也是音乐制作爱好者呢?如果是,那就仔细阅读文章收集对自己有帮助的操作技巧吧~~ FL Studio 21.2.3 Win-安装包下载如下: https://wm.makeding.com/iclk/?zoneid55981 FL Studio 21 .2.3Mac-安装包下载如下: https://wm.makeding.com/iclk/?…

Unity 3D软件下载安装;Unity 3D游戏制作软件资源包获取!

Unity3D,它凭借强大的功能和灵活的特性,在游戏开发和互动内容创作领域发挥着举足轻重的作用。 作为一款顶尖的游戏引擎,Unity3D内置了先进的物理引擎——PhysX。这一物理引擎堪称业界翘楚,能够为开发者提供全方位、高精度的物理模…

东软医疗获通用技术集团战略投资,共创中国医疗设备产业未来

近日,通用技术集团所属资本公司联合中国国有企业混合所有制改革基金有限公司与东软医疗系统股份有限公司(下称“东软医疗”)签署投资协议,战略投资东软医疗。 作为央企和民企携手发展高端医疗设备产业的具体实践,此次…

有什么事在windows上显的顺理成章,在Linux上就很令人费解?

在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「Linux的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!可以假定一个几乎恒久不变的…

基于Java的音乐网站系统01239

目 录 摘要 1 绪论 1.1 研究背景 1.2系统开发目标、意义 1.3研究内容 2 相关技术介绍 2.1 MySQL数据库 2.2 Java编程语言 2.3 SpringBoot框架介绍 3 系统需求分析与设计 3.1 可行性分析 3.1.1 技术可行性分析 3.1.2 经济可行性分析 3.1.3 法律可行性分析 3.2 需…

已成功与服务器建立连接,但是在登录过程中发生错误。(provider: SSL提供程序,error:0-证书链是由不受信任的颁发机构颁发的。)

已成功与服务器建立连接,但是在登录过程中发生错误。(provider: SSL提供程序,error:0-证书链是由不受信任的颁发机构颁发的。) 在连接SQL Server2008R2数据库时发生错误。 连接字符串:server127.0.0.1;uidsa;pwd1;databasedb; 解决办法: 方…

Python--线程基础

相关概念 线程是"轻量级进程",是计算机中CPU进行任务调度的最小单位。 线程属于进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,且至少有一个线程。 每个进程开始的创建的时候,都会随之创建一个主线程。 进程负责分配和隔离资源(CPU, 内存…

2002-2022年各省老年人口抚养比(人口抽样调查)数据

2002-2022年各省老年人口抚养比(人口抽样调查)数据 1、时间:2002-2022年 2、指标:老年人口抚养比 3、来源:国家统计局、统计年鉴 4、范围:31省, 5、缺失情况:无缺失,其中2010年的值取2009、…

人脸嵌入向量提取计算

本文将讨论如何使用开源中提供的预训练模型从图像中提取人脸编码或人脸嵌入。我还附上了代码,请参阅此 git仓库。 NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出…

灌区量测水管理系统是如何实现灌区节水?

随着全球水资源日益紧张,节水已成为农业生产中不可忽视的一环。在灌区管理中,量测水管理系统以其精准的数据监测和科学的灌溉管理,为实现灌区节水提供了强有力的技术支持。 灌区量测水管理系统是一套集成了自动化监测、数据传输、数据分析和…

基于星火大模型的群聊对话分角色要素提取挑战赛|#AI夏令营#Datawhale#夏令营-Lora微调与prompt构造

赛题连接 https://challenge.xfyun.cn/topic/info?typerole-element-extraction&optionphb Datawhale Al夏令营 零基础入门大模型技术竞赛 数据集预处理 由于赛题官方限定使用了星火大模型,所以只能调用星火大模型的API或者使用零代码微调 首先训练数据很少…

fyne一个复杂的布局案例

一个复杂的布局案例 实现如下布局: 布局分析: 代码如下: package mainimport ("complexlayout/icons""fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/canvas""fyne.io/fyne/v2/container""fyne.io/fyne/v2…

昇思MindSpore学习入门-保存与加载

在训练网络模型的过程中,实际上我们希望保存中间和最后的结果,用于微调(fine-tune)和后续的模型推理与部署,本章节我们将介绍如何保存与加载模型。 保存和加载模型权重 保存模型使用save_checkpoint接口,…

在Linux上运行macOS:深度解析OSX-KVM项目

在Linux上运行macOS:深度解析OSX-KVM项目 在现代开发和测试环境中,能够在不同操作系统之间无缝切换是至关重要的。对于开发者而言,如何在Linux系统上运行macOS一直是一个挑战。然而,OSX-KVM项目为我们提供了一种高效的解决方案&a…

rtpengine 项目

目录 !1. 如果容器内部修改 rtpengine 并且让他生效 守护进程模块(daemon) 内核模块(kernel-module) 录音守护进程模块(recording-daemon) iptables扩展模块(iptables-extension) 2. 在Docker容器中编译好四个模块后,您需要采取以下步骤 1. 加载内…

网易云商发布《2024体验增长白皮书》,助力企业找到增长突破点

“过去几年里,当我们做内部审视和自我反思时,我们知道阿里落后了,因为我们忘记了真正的客户是谁。我们的客户是使用APP进行购物的人,而我们没有给他们最好的体验。” 4月3日,在挪威主权财富基金(Norges Ba…

以 Vue 3 项目为例,多个请求下如何全局封装 Loading 的展示与关闭?其中大有学问!

大家好,我是CodeQi! 项目开发中,Loading 的展示与关闭是非常关键的用户体验设计。 当我们的应用需要发起多个异步请求时,如何有效地管理全局 Loading 状态,保证用户在等待数据加载时能有明确的反馈,这是一个值得深入探讨的问题。 本文将以 Vue 3 项目为例,详细讲解如…