<JavaEE> volatile关键字 -- 保证内存可见性、禁止指令重排序
目录
一、内存可见性
1.1 Java内存模型(JMM)
1.2 内存可见性演示
二、指令重排序
三、关键字 volatile
一、内存可见性
1.1 Java内存模型(JMM)
| 1)什么是Java内存模型(JMM)? |
| Java内存模型即Java Memory Model,简称JMM。用于屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各平台下都能够达到一致的内存访问效果,即实现“跨平台”。 |
| 2)JMM中的“主内存”概念和“工作内存”概念 | |
| “主内存” | 硬件中的内存,在JMM中表述为“主内存”,其中存储了线程间的共享变量等数据。 |
| “工作内存” | CPU寄存器和缓存等临时存储区,在JMM中表述为“工作内存”,每个线程都有自己的“工作内存”。 |
| 3)线程和“主内存”、“工作内存”的关系 |
| 当线程需要读取共享变量时,会从“主内存”拷贝至“工作内存”,再从“工作内存”读取。 当线程需要修改共享变量时,会先修改“工作内存”中的数据副本,再将数据同步回“主内存”。 线程运行中,数据的交互是频繁且持续的,而CPU访问自身寄存器和高速缓存的速度远高于访问内存的速度。 因此,采用频繁与“工作内存”交互、需要时再与“主内存”交互的工作策略,有利于提高运行效率,是编译器优化的方式之一。 |
1.2 内存可见性演示
| 什么是内存可见性? |
| 内存可见性是指,线程对共享变量值的修改,能否被其他线程及时察觉。 如果一个线程修改了共享变量值,但没有及时写回内存中,导致其他线程无法获得已修改的正确数据,这就被认为出现了线程安全问题。 内存可见性是导致线程不安全的原因之一。 |
代码演示内存不可见导致线程不安全:
public class Volatile_Demo0 {//有一个共享变量flag,注意该变量没有被 volatile 修饰;public static int flag = 0;public static void main(String[] args) throws InterruptedException {//创建一个线程,线程中当flag为0时,一直循环判断;Thread t = new Thread(()->{while (flag == 0){}});//启动线程;System.out.println("run开始");t.start();//让main线程休眠两秒后,将flag的值改为1;Thread.sleep(2000);flag = 1;//让main线程等待t线程结束;t.join();System.out.println("run结束");}
}//运行结果:
run开始
...程序一直在执行,没有打印“run结束”。
出现了线程安全问题。
上述代码问题分析:
| 程序无法结束的原因是什么? |
| 根据代码,flag 在线程启动两秒后被改为 1 ,此时 t 线程应该因为跳出 while 循环而执行完毕。 但实际情况却不是这样,t 线程没有结束。 正如上文“线程和‘主内存’、‘工作内存’的关系”中提到的,线程读取共享数据到“工作内存中”,再从“工作内存”读取数据。 所以此时在 t 线程中,参与 while 循环条件判断的 flag ,实际上是一个存储在“工作内存”的 flag 副本。 当 flag 通过另一线程改变值,改变的是“主内存”中的 flag,t 线程并不能察觉。 因此 t 线程无法从 while 循环中跳出并结束。 这就是内存可见性影响线程安全的情况之一。 |
二、指令重排序
| 1)什么是指令重排序? |
| 指令重排序是指编译器自动调整原有代码的执行顺序,在保证逻辑不变的前提下,提高程序运行效率。 指令重排序也是编译器优化的方式之一。 |
| 2)指令重排序存在什么问题? |
| 指令重排序的前提是“保证逻辑不变”。这一点在单线程环境下较容易判断,但是在多线程环境下,代码复杂程度高,编译器在编译阶段对代码执行效果的判断存在困难。 因此在多线程环境下,代码重排序很容易导致优化后和优化前的逻辑不等价。 |
图示演示指令重排序可能出现的问题:

三、关键字 volatile
| 1)volatile 的作用是什么? | |
| <1> | 保证内存可见性。volatile 修饰的变量每次被访问都必须从内存中读取,每次被修改都必须存储到内存中。 |
| <2> | 禁止指令重排序。volatile 修饰的变量读写操作的相关指令不允许被重排序。 |
| 2)内存可见性和指令重排序都是编译器优化,怎么好像都是负作用? |
| 在大部分场景下,编译器优化都能非常优秀的提高程序的运行效率,只是在多线程编程的部分关键代码中,存在线程不安全的风险。 |
| 3)volatile 不保证原子性 |
| volatile 和 synchronized 有本质的区别,synchronized 保证原子性,而 volatile 保证的是内存可见性。 |
| 4)合理的使用 volatile 关键字 |
| 编译器优化就好像一场激烈的风暴,而程序员要做的就是掌控这场风暴,必要时让风暴停一停。 为此,Java 提供了 volatile 关键字供程序员使用。当使用 volatile 关键字时,强制读写内存,禁止指令重排序,程序运行速度变慢,但数据准确性提高,线程变得安全了。 |
代码演示 volatile 的使用效果,沿用上文“内存可见性演示”中的代码:
public class Volatile_Demo0 {//有一个共享变量flag,注意该变量已经被 volatile 修饰;public volatile static int flag = 0;public static void main(String[] args) throws InterruptedException {//创建一个线程,线程中当flag为0时,一直循环判断;Thread t = new Thread(()->{while (flag == 0){}});//启动线程;System.out.println("run开始");t.start();//让main线程休眠两秒后,将flag的值改为1;Thread.sleep(2000);flag = 1;//让main线程等待t线程结束;t.join();System.out.println("run结束");}
}//运行结果:
run开始
run结束与上文“内存可见性演示”中的代码唯一的不同,就是在共享变量 flag 上,使用了 volatile 进行修饰。
但这次的结果是程序正常执行完毕,证明了 volatile 的作用。
相关文章:
<JavaEE> volatile关键字 -- 保证内存可见性、禁止指令重排序
目录 一、内存可见性 1.1 Java内存模型(JMM) 1.2 内存可见性演示 二、指令重排序 三、关键字 volatile 一、内存可见性 1.1 Java内存模型(JMM) 1)什么是Java内存模型(JMM)?Java内存模型即Java Memory Model,简…...
docker安装mysql8
docker安装mysql8 docker search mysql:8 #搜索可以使用的msyql8的镜像 docker pull mysql:8.0.27 #拉去mysql8的镜像 创建挂载的宿主机目录 mkdir -p /data/mysql/mysql8/conf # 配置文件目录 mkdir -p /data/mysql/mysql8/data # 数据目录 touch /data/mysql/mysql8/conf/my.…...
消息丢失排查方法?
遇到丢消息问题,如果是单聊,群聊,聊天室,系统消息可以在开发者后台北极星自助查询一下消息是否发送成功。根据您实际发送的相关信息(发送者、接收者、时间、消息 ID ……)看是否可以查到消息 如果消息查不到…...
Linux 匿名页反向映射
1. 何为反向映射 正向映射: 用户进程在申请内存时,内核并不会立刻给其分配物理内存,而是先为其分配一段虚拟地址空间,当进程访问该虚拟地址空间时,触发page fault异常,异常处理流程中会为其分配物理页面&am…...
国内首个农业开源鸿蒙操作系统联合华为正式发布
2023年11月29日,在中国国际供应链促进博览会上,中信农业科技股份有限公司(简称“中信农业”)与深圳开鸿数字产业发展有限公司(简称“深开鸿”)以及华为技术有限公司(简称“华为”)联…...
python HTML文件标题解析问题的挑战
引言 在网络爬虫中,HTML文件标题解析扮演着至关重要的角色。正确地解析HTML文件标题可以帮助爬虫准确地获取所需信息,但是在实际操作中,我们常常会面临一些挑战和问题。本文将探讨在Scrapy中解析HTML文件标题时可能遇到的问题,并…...
AIM: Symmetric Primitive for Shorter Signatures with Stronger Security
目录 笔记后续的研究方向摘要引言贡献 AIM: Symmetric Primitive for Shorter Signatures with Stronger Security CCS 2023 笔记 后续的研究方向 摘要 基于头部MPC(MPCitH)范式的后量子签名方案最近引起了人们的极大关注,因为它们的安全性…...
【 Go语言使用xorm框架操作数据库】
Go语言使用xorm框架操作数据库 Xorm 是一个简单而强大的Go语言ORM(对象关系映射)库。它支持自动将结构体映射到数据库表,并提供了一系列便捷的API来执行CRUD(创建、读取、更新和删除)操作。 安装 Xorm 首先…...
DouyinAPI接口系列丨Douyin商品详情数据接口丨Douyin视频详情数据接口
抖音商品详情API是抖音开放平台提供的一套API接口,用于获取商品详情信息。通过该API,开发者可以获取到商品的详细信息,包括商品ID、名称、描述、价格、销量、评价等信息。 在使用抖音商品详情API之前,需要先注册并登录抖音开放平…...
旺店通对接中国南方电网,打破跨系统连接,让数据轻易互通成为现实
接入系统:旺店通企业版 旺店通是北京掌上先机网络科技有限公司旗下品牌,国内的零售云服务提供商,基于云计算SaaS服务模式,以体系化解决方案,助力零售企业数字化智能化管理升级。为零售电商企业的订单管理及仓储管理提供…...
简介Kadane算法及相关的普通动态规划
简介Kadane算法及相关的普通动态规划 本文详细论述Kadane算法的经典题目,并通过“首先列出动态规划解法,再改为Kadane算法解法”的方式,讲解二者的不同。最后给出一道Kadane算法变体的题目,解法极为简洁优美。 Kadane算法也是一…...
校园教务管理系统
学年论文(课程设计) 题目: 信息管理系统 校园教务管理系统 摘要:数据库技术是现代信息科学与技术的重要组成部分,是计算机数据处理与信息管理系统的核心,随着计算机技术的发展,数据库技…...
【LeetCode热题100】【双指针】接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] …...
软件工程-(可行性分析、需求分析)
目录 一.可行性研究 1.1定义 1.2项目背景 1.3三方面研究目标系统的可行性 1.3.1技术可行性分析 1.3.2 经济可行性分析 1.3.3 市场可行性分析 1.4. 数据流图 数据字典(DD) 1.5风险评估 1.6结论与建议 二、需求分析 引言 项目概述 利益相关者分析…...
HuggingFace学习笔记--BitFit高效微调
1--BitFit高效微调 BitFit,全称是 bias-term fine-tuning,其高效微调只去微调带有 bias 的参数,其余参数全部固定; 2--实例代码 from datasets import load_from_disk from transformers import AutoTokenizer, AutoModelForCaus…...
阅读笔记|A Survey of Large Language Models
阅读笔记 模型选择:是否一定要选择参数量巨大的模型?如果需要更好的泛化能力,用于处理非单一的任务,例如对话,则可用选更大的模型;而对于单一明确的任务,则不一定越大越好,参数小一…...
JSP 设置静态文件资源访问路径
这里 我们先在 WEB目录webapp 下创建一个包 叫 static 就用它来存静态资源 然后 我们扔一张图片进去 我们直接这样写 如下图 找到父级目录 然后寻找下面的 static 下的 img.png 运行代码 很明显 它没有找到 这边 我们直接找到 webapp目录下的 WEB-INF目录下的 web.xml 加入…...
【Pytorch】Visualization of Feature Maps(4)——Saliency Maps
学习参考来自 Saliency Maps的原理与简单实现(使用Pytorch实现)https://github.com/wmn7/ML_Practice/tree/master/2019_07_08/Saliency%20Maps Saliency Maps 原理 《Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps》&…...
java第三十课
电商项目(前台): 登录接口 注册接口后台: 注册审核:建一个线程类 注意程序中的一个问题。 这里是 5 条记录,2 条记录显示应该是 3 页,实际操作过程 有审核机制,出现了数据记录动态变…...
Scala--2
package scala02object Scala07_typeCast {def main(args: Array[String]): Unit {// TODO 隐式转换// 自动转换val b: Byte 10var i: Int b 10val l: Long b 10 100Lval fl: Float b 10 100L 10.5fval d: Double b 10 100L 10.5f 20.00println(d.getClass…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
