【Java】volatile
一、volatile
volatile是Java虚拟机提供的轻量级的同步机制,它有3个特性:
1)保证可见性
2)不保证原子性
3)禁止指令重排
- 当写一个
volatile变量时,JMM会把该线程对应的本地内存中的共享变量值立即刷新回主内存中 - 当读一个
volatile变量时,JMM会把该线程对应的本地内存设置为无效,直接从主内存中读取共享变量
所以volatile的写内存语义是直接刷新到主内存中,读的内存语义是直接从主内存中读取
1. 可见性
保证不同线程对这个变量进行操作时的可见性,即变量一旦改变所有线程立即可见 。
使用volatile修饰共享变量,被volatile修改的变量有以下特点:
- 线程中读取的时候,每次读取都会去主内存中读取共享变量最新的值,然后将其复制到工作内存
- 线程中修改了工作内存中变量的副本,修改之后会立即刷新到主内存
从volatile变量的读写过程分析:
要
use(使用)一个变量的时候必需load(载入),要载入的时候必需从主内存read(读取)这样就解决了读的可见性。写操作是把assign(赋值)和store(存储)做了关联(在assign(赋值)后必需store(存储)),store(存储)后write(写入)。 也就是做到了给一个变量赋值的时候一串关联指令直接把变量值写到主内存。 就这样通过用的时候直接从主内存取,在赋值到直接写回主内存做到了内存可见性。
2. 无原子性
原子性指的是一个操作是不可中断的,即使是在多线程环境下,一个操作一旦开始就不会被其他线程影响。
多线程环境下,“数据计算”和“数据赋值”操作可能多次出现,即操作非原子。若数据在加载之后,若主内存count变量发生修改之后,由于线程工作内存中的值在此前已经加载,从而不会对变更操作做出相应变化,即私有内存和公共内存中变量不同步,进而导致数据不一致。
对于volatile变量,JVM只是保证从主内存加载到线程工作内存的值是最新的,也就是数据加载时是最新的。由此可见volatile解决的是变量读时的可见性问题,但无法保证原子性,对于多线程修改共享变量的场景必须使用加锁同步。
以i++为例,不具备原子性,该操作是先读取值,然后写回一个新值,相当于原来的值加上1,分3步完成。

如果第二个线程在第一个线程读取旧值和写回新值期间(上图所指三步期间)读取i的域值,那么第二个线程就会与第一个线程一起看到同一个值,并执行相同值的加1操作,这也就造成了线程安全失败,因此对于add方法必须使用synchronized修饰,以便保证线程安全。
从volatile变量的读写过程分析:
read-load-use和assign-store-write成为了两个不可分割的原子操作,但是在use和assign之间依然有极小的一段真空期,有可能变量会被其他线程读取,导致写丢失一次
3. 指令禁重排
重排序:
是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段,有时候会改变程序语句的先后顺序。
- 不存在数据依赖关系,可以重排序;
- 存在数据依赖关系,禁止重排序 。
但重排后的指令绝对不能改变原有的串行语义。
数据依赖性:若两个操作访问同一变量,且这两个操作中有一个为写操作,此时两操作间就存在数据依赖性
重排序的分类和执行流程 :
-
编译器优化的重排序:编译器在不改变单线程串行语义的前提下,可以重新调整指令的执行顺序
-
指令级并行的重排序:处理器使用指令级并行技术来将多条指令重叠执行,若不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
-
内存系统的重排序:由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是乱序执行

volatile有关禁重排的行为:
-
当第一个操作为
volatile读时,不论第二个操作是什么,都不能重排序。这个操作保证了volatile读之后的操作不会被重排到volatile读之前(volatile读之后的操作,都禁止重排序到volatile之前) -
当第二个操作为
volatile写时,不论第一个操作是什么,都不能重排序。这个操作保证了volatile写之前的操作不会被重排到volatile写之后 (volatile写之前的操作,都禁止重排序到volatile之后) -
当第一个操作为
volatile写时,第二个操作为volatile读时,不能重排。(volatile写之后volatile读,禁止重排序的)
内存屏障四大指令插入情况:
-
在每个
volatile写操作的前面插入一个StoreStore屏障,保证在volatile写之前,其前面的所有普通写操作都已经刷新到主内存中。 -
在每个
volatile写操作的后面插入一个StoreLoad屏障,避免volatile写与后面可能有的volatile读/写操作重排序 -
在每个
volatile读操作的后面插入一个LoadLoad屏障,禁止处理器把上面的volatile读与下面的普通读重排序。 -
在每个
volatile读操作的后面插入一个LoadStore屏障,禁止处理器把上面的volatile读与下面的普通写重排序。
二、如何正确使用volatile
由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁(使用synchronized、java.util.concurrent中的锁或原子类)来保证原子性:
- 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。
- 变量不需要与其他的状态变量共同参与不变约束。
1. 单一赋值可以,但是含复合运算赋值不可以(i++之类)
volatile int a = 10;
2. 状态标志,判断业务是否结束
使用:作为一个布尔状态标志,用于指示发生了一个重要的一次性事件,例如完成初始化或任务结束
理由:状态标志并不依赖于程序内任何其他状态,且通常只有一种状态转换
例子:判断业务是否结束
volatile boolean flag = false
3. 开销较低的读,写锁策略
使用:当读远多于写,结合使用内部锁和volatile变量来成少同步的开销 。
理由:
- 利用
volatile保证读取操作的可见性; - 利用
synchronized保证复合操作的原子性。
4. DCL双端锁的发布
隐患:多线程环境下,由于重排序,该对象可能还未完成初始化就被其他线程读取
修正方法1:加volatile(也即正确的DCL双端锁)
原理:利用volatile, 禁止"初始化对象"和"设置singleton指向内存空间"的重排序
修正方法2:静态内部类
相关文章:
【Java】volatile
一、volatile volatile是Java虚拟机提供的轻量级的同步机制,它有3个特性: 1)保证可见性 2)不保证原子性 3)禁止指令重排 当写一个volatile变量时,JMM会把该…...
混沌工程 Chaos Mesh 实践经验(持续更新)
使用 k8s JVM故障 Linux内核版本 Linux 系统内核必须为 4.1 及以上版本。 不然会一直失败,可以从Chaos Mesh dashboard前端看到。 对native方法注入故障无效 实测对Thread.sleep(Long) 注入故障无效,猜测是因为对native方法无效,大概因为…...
追梦之旅【数据结构篇】——详解C语言实现链栈
详解C语言实现链栈~😎前言🙌整体实现内容分析💞1.头文件编码实现🙌2.功能文件编码实现🙌3.测试函数功能代码🙌总结撒花💞😎博客昵称:博客小梦 😊最喜欢的座右…...
oracle数据库常用操作
1.连接登录切换用户su - oracle以管理员模式登录到sqlplus:sqlplus / as sysdba oracle登录身份有三种:1.1Normal 普通身份;1.2.sysdba 系统管理员身份;若以 ‘sysdba’ 方式认证,登录用户为 ‘SYS’,为 Or…...
一文教会你如何在Linux系统中使用Docker安装Redis 、以及如何使用可视化工具连接【详细过程+图解】
文章目录1、安装redis2、在外部创建配置文件3、创建redis4、启动测试redis5、数据持久化存储6、使用可视化工具连接redis前言在windows上安装过reids、在linux上也安装过redis,但是都没有docker上安装redis方便。这里给出docer安装redis的相关教程1、安装redis 默认…...
mysql 内存架构
1. 背景 从 innodb 的整体架构中可以知道 innodb 的内存架构中分为 buffer pool 缓存区, change pool 修改缓冲区, adaptive hash index 自适应哈希索引, 和 log buffer 日志缓冲区. 2. buffer pool buffer pool 是用于缓冲磁盘页的数据,mysql 的80%的内存会分配给…...
Helm安装Harbor
一、介绍 1.1 Harbor Harbor 是由 VMware 公司为企业用户设计的 Registry Server 开源项目,包括了权限管理 (RBAC)、LDAP、审计、管理界面、自我注册、HA 等企业必需的功能,同时针对中国用户的特点,设计镜像复制和中文支持等功能。目前该项…...
梯度下降优化器:SGD -> SGDM -> NAG ->AdaGrad -> AdaDelta -> Adam -> Nadam -> AdamW
目录 1 前言 2 梯度概念 3 一般梯度下降法 4 BGD 5 SGD 6 MBGD 7 Momentum 8 SGDM(SGD with momentum) 9 NAG(Nesterov Accelerated Gradient) 10 AdaGrad 11 RMSProp 12 Adadelta 13 Adam 13 Nadam 14 AdamW 15 Lion(EvoLve…...
Ubuntu下gcc多版本管理
Ubuntu下多gcc版本的管理 开发过程中,在编译一个开源项目时,由于代码使用的c版本过高,而系统内置的gcc版本过低时,这个时候我们就需要升级gcc版本,但是为了避免兼容性问题,安装多个版本的gcc,然…...
吃透8图1模板,人人可以做架构
前言 在40岁老架构师 尼恩的读者交流群(50)中,很多小伙伴问尼恩: 大佬,我们写架构方案, 需要从哪些方面展开 大佬,我们写总体设计方案需要一些技术亮点,可否发一些给我参考下 诸如此类,问法很多…...
骨传导耳机推荐哪款好,列举几款是市面上热销的骨传导耳机
骨传导耳机是一种新型的耳机类型,通过震动和声音将振动传到了耳道外,对耳道不会产生损伤,能够保护听力。相比于传统耳机的优势有很多,比如运动时佩戴更加稳固,也可以在听歌时与人交谈。但在市面上的骨传导耳机款式可…...
CFS三层内网渗透
目录 环境搭建 拿ubuntu主机 信息收集 thinkphp漏洞利用 上线msf 添加路由建立socks代理 bagecms漏洞利用 拿下centos主机 msf上线centos 添加路由,建立socks代理 拿下win7主机 环境搭建 设置三块虚拟网卡 开启虚拟机验证,确保所处网段正确&a…...
SQL server设置用户只能访问特定数据库、访问特定表或视图
在实际业务场景我们可能需要开放单独用户给第三方使用,并且不想让第三方看到与业务不相关的表或视图,我们需要在数据库中设置一切权限来实现此功能: 1.设置用户只能查看数据库中特定的视图或表 1.创建用户名 选择默认数据库 服务器角色默认…...
linux:http服务器搭建及实验案例
目录准备工作http服务器各个配置文件大概说明实验1:访问不同ip获得不同网页实验2:同一ip访问不同端口获得不同网页准备工作 1,安装http服务 2,将 /etc/selinux/config 文件下面的 SELINUX值改为 disabled 或者 permissive 。 3&a…...
【无标题】智能工业安全用电监测与智慧能源解决方案
工业互联网已成为全球制造业发展的新趋势。在新基建的推动下,5G、人工智能、云计算等技术与传统工业深度融合,为实现智能制造提供了技术支撑,将有力促进制造强国早日实现。 十四五规划在新基建的基础上进一步加快了制造业转型升级的步伐&…...
前端白屏的检测方案,让你知道自己的页面白了
前言 页面白屏,绝对是让前端开发者最为胆寒的事情,特别是随着 SPA 项目的盛行,前端白屏的情况变得更为复杂且棘手起来( 这里的白屏是指页面一直处于白屏状态 ) 要是能检测到页面白屏就太棒了,开发者谁都不…...
编译原理【文法设计】—每个a后面至少一个b、ab个数相等,ab个数不相等的所有串
编译原理【文法设计】—设计每个a后面至少一个b、ab个数相等,ab个数不相等的文法为字母表Σ{a,b}Σ\{a,b\}Σ{a,b}上的下列每个语言设计一个文法 (a) 每个a后面至少有一个b的所有串 首先,每个a后面至少有一个b的正规式怎么写呢?每个a都需要…...
【死磕数据库专栏启动】在CentOS7中安装 MySQL5.7版本实战
文章目录前言实验环境一. 安装MySQL1.1 配置yum源1.2 安装之前的环境检查1.3 下载MySQL的包1.4 开始使用yum安装1.5 启动并测试二. 设置新密码并重新启动2.1 设置新密码2.2 重新登录测试总结前言 学习MySQL是一件比较枯燥的事情,学习开始之前要先安装MySQL数据库&a…...
23.2.23 22湖北省赛 B
好久没打卡了, 随便找的个水题写 这题是简单难度的 ab1 所以可以找到固定规律, 通过手动模拟可以发现 假设两种水叫做a水和b水 先倒入a水 1:0 倒入b水 1:1 此时水杯为 倒出一半的混合物, 因为ab水互溶, 比例不变 再加入a水或者b水将容器填满 比例现在变为 3:1 混合之后再…...
ONLYOFFICE中的chatGPT 是如何编写毕业论文以及翻译多种语言的
前言 chatGPT这款软件曾被多个国家的大学禁用,我们也多次在网上看到chatGPT帮助应届毕业生编写毕业答辩论文,但是这款软件目前还没有在国内正式上线,ONLYOFFICE7.3版本更新后呢,就添加了chatGPT该功能,并且正常使用。 …...
JMeter压测5大底层优化:线程模型、HTTP连接、Groovy脚本、JVM参数与分布式协同
1. 为什么90%的JMeter脚本在压测中“假成功”——从一个被忽略的线程组配置说起你有没有遇到过这样的情况:脚本在JMeter GUI里跑得飞快,聚合报告里TPS稳稳上200,响应时间平均80ms,看起来一切完美;可一上生产环境做真实…...
强化学习入门ⅡCS188 Note10 学习笔记
更好的阅读体验 Approximate Q-learning Q-learning虽然很有优势,但是缺乏了泛化能力。当pacman学习了figure1中的困境后,智能体是不会意识到figure2,figure3中的情景和figure1中的困境基本一样 所以说Q-Learning很有局限性,这时候该算法…...
告别调参噩梦!用Ball k-means在Python里5分钟搞定百万级数据聚类
百万级数据聚类的革命:用Ball k-means实现Python高效实战 当你的数据集膨胀到百万级别时,传统k-means算法突然变得像老牛拉车——迭代缓慢、调参困难、内存告急。我曾在一个电商用户分群项目中,面对120万条用户行为数据,sklearn的…...
AI赋能工程教育:构建个性化、多元化与伦理驱动的学习生态
1. 项目概述:当工程教育遇见AI,我们到底在谈论什么?最近几年,AI这个词快被说烂了。从ChatGPT的横空出世,到各类生成式AI工具的遍地开花,似乎每个行业都在讨论如何“被赋能”。工程教育这个领域也不例外&…...
量子互联网:原理、挑战与未来应用
1. 量子互联网的技术本质与核心价值量子互联网并非传统互联网的简单升级,而是一种基于量子力学原理的全新通信范式。其核心在于利用量子纠缠这一独特物理现象,实现传统通信手段无法企及的功能。在传统互联网中,信息以经典比特(0或…...
不用pip install -e也能搞定Vision Mamba训练:我的CIFAR-100快速测试与whl文件安装指南
Vision Mamba极速体验指南:绕过复杂安装直接训练CIFAR-100 当最新论文《Vision Mamba: Efficient Visual Representation Learning with Bidirectional State Space Model》在arXiv上出现时,许多同行都迫不及待想验证这个号称"超越ViT"的架构…...
去偏机器学习在交通行为因果推断中的应用:从关联分析到因果效应评估
1. 项目概述:当交通研究遇上因果推断在交通工程与城市规划领域,我们常常面临一个核心挑战:如何从海量的观测数据中,剥离出某个特定因素(比如一项新政策、一种交通管控措施)对人们行为的“真实”影响&#x…...
鸿蒙今日穿搭页面构建:单品清单、一周搭配日历与穿搭提示模块详解
鸿蒙今日穿搭页面构建:单品清单、一周搭配日历与穿搭提示模块详解 前言 在 HarmonyOS 6.0 应用开发中,穿搭类页面的单品管理、周计划安排和温馨提醒是完善用户体验的重要补充模块。本文将以“今日穿搭”应用中的“单品清单”网格模块、“一周搭配日历”周…...
从ISA到PCIe:为什么老电脑升级显卡要插对槽?聊聊PCI总线的那些事儿
从ISA到PCIe:老电脑升级显卡必须知道的插槽进化史 当你从储物间翻出一台2003年的戴尔Dimension 4600准备升级显卡时,会发现主板上那些长短不一的插槽仿佛在讲述一段被遗忘的技术史诗。黑色PCI插槽旁紧挨着棕色的AGP 8X,而最边缘那个几乎被灰尘…...
Deepseek-V4-Flash 高效应用实战指南
文章目录① 高并发客服场景下的实时响应优化② 电商大促期间的海量商品描述生成③ 教育领域个性化习题与解析快速定制④ 短视频脚本批量创作与分镜规划⑤ 跨语言文档即时翻译与本地化适配⑥ 代码辅助生成与常见 Bug 自动修复⑦ 社交媒体热点内容敏捷生产流程⑧ 企业内部知识库智…...
