解决Java并发可见性问题,Volatile闪亮登场

完美解决java并发可见性问题,volatile闪亮登场 这篇文章尝试站在年轻同学的角度,用最简单的大白话,加上多张图给大家说一下,volatile到底是什么? 阅读详情

场景引入,问题初现

很多同学出去面试,都会被问到一个常见的问题:说说你对volatile的理解?

不少初出茅庐的同学可能会有点措手不及,因为可能就是之前没关注过这个。但是网上百度一下呢,不少文章写的很好,但是理论扎的太深,文字太多,图太少,让人有点难以理解。

基于上述痛点,这篇文章尝试站在年轻同学的角度,用最简单的大白话,加上多张图给大家说一下,volatile到底是什么?

当然本文不会把理论扎的太深,因为一下子扎深了文字太多,很多同学还是会不好理解。

本文仅仅是定位在用大白话的语言将volatile这个东西解释清楚,而涉及到特别底层的一些原理和技术问题,以后有机会开文再写。

首先,给大家上一张图,咱们来一起看看:

如上图,这张图说的是java内存模型中,每个线程有自己的工作内存,同时还有一个共享的主内存。

举个例子,比如说有两个线程,他们的代码里都需要读取data这个变量的值,那么他们都会从主内存里加载data变量的值到自己的工作内存,然后才可以使用那个值。

好了,现在大家从图里看到,每个线程都把data这个变量的副本加载到了自己的工作内存里了,所以每个线程都可以读到data = 0这个值。

这样,在线程代码运行的过程中,对data的值都可以直接从工作内存里加载了,不需要再从主内存里加载了。

那问题来了,为啥一定要让每个线程用一个工作内存来存放变量的副本以供读取呢?我直接让线程每次都从主内存加载变量的值不行吗?

很简单!因为线程运行的代码对应的是一些指令,是由CPU执行的!但是CPU每次执行指令运算的时候,也就是执行我们写的那一大坨代码的时候,要是每次需要一个变量的值,都从主内存加载,性能会比较差!

所以说后来想了一个办法,就是线程有工作内存的概念,类似于一个高速的本地缓存。

这样一来,线程的代码在执行过程中,就可以直接从自己本地缓存里加载变量副本,不需要从主内存加载变量值,性能可以提升很多!

但是大家思考一下,这样会有什么问题?

我们来设想一下,假如说线程1修改了data变量的值为1,然后将这个修改写入自己的本地工作内存。那么此时,线程1的工作内存里的data值为1。

然而,主内存里的data值还是为0!线程2的工作内存里的data值还是0啊?!

这可尴尬了,那接下来,在线程1的代码运行过程中,他可以直接读到data最新的值是1,但是线程2的代码运行过程中读到的data的值还是0!

这就导致,线程1和线程2其实都是在操作一个变量data,但是线程1修改了data变量的值之后,线程2是看不到的,一直都是看到自己本地工作内存中的一个旧的副本的值!

这就是所谓的java并发编程中的可见性问题:

多个线程并发读写一个共享变量的时候,有可能某个线程修改了变量的值,但是其他线程看不到!也就是对其他线程不可见!

volatile的作用及背后的原理

那如果要解决这个问题怎么办呢?这时就轮到volatile闪亮登场了!你只要给data这个变量在定义的时候加一个volatile,就直接可以完美的解决这个可见性的问题。

比如下面的这样的代码,在加了volatile之后,会有啥作用呢?

完整的作用就不给大家解释了,因为我们定位就是大白话,要是把底层涉及的各种内存屏障、指令重排等概念在这里带出来,不少同学又要蒙圈了!

我们这里,就说说他最关键的几个作用是啥?

第一,一旦data变量定义的时候前面加了volatile来修饰的话,那么线程1只要修改data变量的值,就会在修改完自己本地工作内存的data变量值之后,强制将这个data变量最新的值刷回主内存,必须让主内存里的data变量值立马变成最新的值!

整个过程,如下图所示:

第二,如果此时别的线程的工作内存中有这个data变量的本地缓存,也就是一个变量副本的话,那么会强制让其他线程的工作内存中的data变量缓存直接失效过期,不允许再次读取和使用了!

整个过程,如下图所示:

第三,如果线程2在代码运行过程中再次需要读取data变量的值,此时尝试从本地工作内存中读取,就会发现这个data = 0已经过期了!

此时,他就必须重新从主内存中加载data变量最新的值!那么不就可以读取到data = 1这个最新的值了!整个过程,参见下图:

bingo!好了,volatile完美解决了java并发中可见性的问题!

对一个变量加了volatile关键字修饰之后,只要一个线程修改了这个变量的值,立马强制刷回主内存。

接着强制过期其他线程的本地工作内存中的缓存,最后其他线程读取变量值的时候,强制重新从主内存来加载最新的值!

这样就保证,任何一个线程修改了变量值,其他线程立马就可以看见了!这就是所谓的volatile保证了可见性的工作原理!

总结 & 提醒

最后给大家提一嘴,volatile主要作用是保证可见性以及有序性。

有序性涉及到较为复杂的指令重排、内存屏障等概念,本文没提及,但是volatile是不能保证原子性的!

也就是说,volatile主要解决的是一个线程修改变量值之后,其他线程立马可以读到最新的值,是解决这个问题的,也就是可见性!

但是如果是多个线程同时修改一个变量的值,那还是可能出现多线程并发的安全问题,导致数据值修改错乱,volatile是不负责解决这个问题的,也就是不负责解决原子性问题!​

volatile和synchronized到底啥区别?多图文讲解告诉你 - 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 - If you can NOT explain it simply, you do NOT understand it well enough 现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star 之前写了几篇 Java并发编程的系列 文章,有个朋... 阅读详情

相关推荐

Java 并发⾯试问题之 volatile 到底是什么?

场景引入,问题初现 很多同学出去⾯试,都会被问到⼀个常⻅的问题:说说你对 volatile 的理解? 不少初出茅庐的同学可能会有点措⼿不及,因为可能就是之前没关注过这个。但是⽹上百度⼀下呢,不少⽂章写的很好,但是理论扎的太深,⽂字太多,图太少,让⼈有点难以理解。 基于上述痛点,这篇⽂章尝试站在年轻同学的⻆度,⽤最简单的⼤⽩话,加上多张图给⼤家说⼀下,volatile 到底是什么? 当然本⽂不会把理论扎的太深,因为⼀下⼦扎深了⽂字太多,很多同学还是会不好理解。 本⽂仅仅是定位在⽤⼤⽩话的语⾔将 volatil

码上代码的博客 1万+

Java并发编程之可见性分析 volatile

例如,线程A和线程B,它们都是直接修改主内存中的共享变量,无论是线程A修改了共享变量,还是线程B修改了共享变量,则另一个线程从主内存中读取出来的变量值,一定是修改过的值,这就是线程的可见性。这些线程都是运行在同一个CPU上,操作的是同一个CPU的缓存,只要其中一个线程修改了共享变量的值,那另外的线程就一定能够访问到修改后的变量值。例如,上面的图中,由于CPU是多核的,线程A操作的是CPU-01上的缓存,线程B操作的是CPU-02上的缓存,此时,线程A对变量V的修改对线程B是不可见的,反之亦然。

m0_73311735的博客 1447

【大模型微调】魔搭社区GPU进行LLaMA-Factory微调大模型自我认知

本教程介绍如何使用魔搭社区GPU资源和LLaMA-Factory工具进行大模型微调。主要内容包括环境配置、工具安装、模型训练和效果评估。通过LoRA算法进行自我认知微调,详细说明了从数据准备到模型导出的完整流程,并提供了参数调优和显存管理等实用技巧,帮助读者快速掌握大模型定制化训练方法。

LChuck的博客 2926

Java 之 volatile 详解

volatile 可以看做是轻量级的 synchronized,它只保证了共享变量的可见性,是Java虚拟机提供的轻量级的同步机制。在线程 A 修改被 volatile 修饰的共享变量之后,线程 B 能够读取到正确的值。Java 在多线程中操作共享变量的过程中,会存在指令重排序与共享变量工作内存缓存的问题。volatile 一共有三大特性,保证可见性不保证原子性禁止指令重排。

流华追梦的专栏 8520

FPGA工程师必看:JESD204B同步机制实战指南(含SYSREF信号调试技巧)

本文为FPGA工程师提供了一份JESD204B同步机制的实战指南,重点聚焦于SYSREF信号的调试技巧。文章从同步的核心逻辑出发,深入剖析了时钟、SYSREF与对齐序列这“三驾马车”的协作,并详细阐述了硬件PCB布局、FPGA IP核配置、状态机监控以及使用示波器进行波形分析等关键实战步骤,旨在帮助工程师解决多通道高速系统中的同步难题,确保链路的稳定与确定性延迟。

weixin_29239661的博客 332

自抗扰控制ADRC原理解析及案例应用

ESO的设计通常基于系统动态方程的线性化或近似模型,其输出包括系统状态的估计值和总扰动的估计值。非线性状态误差反馈控制律(Nonlinear State Error Feedback,NLSEF)是ADRC的最后一个环节,负责根据ESO和TD提供的信息生成控制信号。ADRC的另一个重要发展方向是与其他控制策略的融合,如模糊控制、神经网络和自适应控制等,以进一步提高系统的鲁棒性和适应性。ADRC的参数主要包括扩张状态观测器(ESO)的参数和非线性状态误差反馈控制律(NLSEF)的参数。

LIUMAO99的博客 9284

Java 三大并大特性-可见性介绍(结合代码、分析源码)

在并发编程中分析线程安全的问题时往往需要切入点,这其中就包含三条性质:原子性,有序性和可见性。JMM(Java内存模型)就是基于这三个特性展开的,前面的文章中我们已经分析了原子性,现在我们结合代码和字节码、以及jvm hotspot源码一起来看下可见性。

qq_25409421的博客 2232

基于PCA的故障诊断方法(matlab)

1. PCA原理分析 PCA的原理主要是将原始数据进行降维。其具体工作原理参照:CodingLabs - PCA的数学原理 2. 数据预处理 训练数据集(只有正样本)为维数据,即有n个采样值,每个采样值有m个特征。 2.1 数据归一化 将数据X针对每个特征归一化为均值为0,均方根为1的数据。 其中: 3. PCA降维 3.1 首先求取协方差矩阵 协方差矩阵的公式为: 计算出来的协方差矩阵为特征m*m维矩阵。 3.2 求取特征值和特征向量 求取协方差矩阵R的特征值.

tangxianyu的博客 1万+

Java volatile关键字:你真的懂了吗?

可见性问题是指一个线程对共享变量的修改可能不被其他线程立即感知。volatile 通过强制线程从主内存中读取变量的值,而不是从线程的本地缓存中,来解决可见性问题。这确保了一个线程对 volatile 变量的修改对其他线程是可见的。

Hanko的专栏 1764

华为OD机考双机位C卷 - 简单的解压缩算法 (Java & Python & JS & GO & C++ & C)

华为OD机考双机位C卷 - 简单的解压缩算法 , 提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。

算法大师! 130

Ceres&OpenCV 单目相机标定(论文复现)

Ceres&OpenCV 单目相机标定(论文复现)

dayuhaitang1的博客 370

Java volatile的可见性

1.可见性 比如共享变量里有变量A = 25 ,当线程 A 和线程 B 同时去内存获取到变量数据是,AB的本地内存数据值都为25 当线程A改变值为35时,因为线程B和线程A不是统一线程,无法得到最新的改变值,而线程A进行改变之后会去修改主内存值,如果变量为volatile 修饰的话,就会及时通知线程B进行进行访问修改。 ...

qq_37753687的博客 280

ABAP CDS HAVING 全解析:聚合之后的精准过滤、最佳实践与可运行示例

摘要: 本文针对具备ABAP与CDS基础的开发者,详解HAVING在ABAP CDS中的核心用法。HAVING专用于过滤GROUP BY后的聚合结果(如SUM、COUNT),与WHERE的分工明确:前者处理聚合值,后者过滤原始记录。通过销售额阈值、质量分析、财务对账三类典型场景,结合性能优化建议(如优先使用WHERE索引过滤),说明实际应用。文中提供经典CDS View与View Entity两种实现代码,并附Open SQL消费示例,帮助开发者快速落地。常见误区(如聚合条件误写至WHERE)与规避方法亦被

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 221

Java并发面试问题之volatile到底是什么?

本文转载自公众号:石杉的架构笔记,阅读大约需要7分钟。一、写在前面前段时间把几年前带过的一个项目架构演进的过程整理了一个系列出来,参见(《亿级流量架构系列专栏总结》)。不...

阿杜的世界 1005

Hermes Agent 桌面版安装部署完全指南:一步步安装自进化Agent智能体

是由开发的开源自主 AI 智能体(MIT 协议)。它不是绑定在集成编辑器上的编码助手,也不是围绕单一 API 的聊天机器人封装——它是一个越用越强大的自主智能体,拥有独一无二的闭环学习系统特性说明自主技能创建在复杂任务后自动生成可复用的 Skills(技能)技能自我改进使用过程中持续优化已有技能持久化记忆跨会话记住你的项目、偏好和解决方案用户画像建模通过 Honcho 方言式推理,逐步构建对你的深度理解20+ 平台接入。

大模型与Agent智能体 7763

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

深度剖析 volatile 可见性

在多线程并发编程中,volatile是轻量级的synchronized,用好volatile是Java开发的同学必备技能之一。 前言 volatile是变量修饰符,其修饰的变量具有可见性。在Java中为了加快程序的运行效率,对一些变量的操作通常是在寄存器或是cpu缓存上进行的,之后才会同步到内存中,而加了volatile修饰符的变量则是直接读写内存。可见性也就说...

3954

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Java并发面试问题之volatile到底是什么

Java并发面试问题之volatile到底是什么

weixin_38598961的博客 163

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

大白话聊聊Java并发面试问题之volatile到底是什么?

大白话聊聊Java并发面试问题之volatile到底是什么?【石杉的架构笔记】 一、写在前面 前段时间把几年前带过的一个项目架构演进的过程整理了一个系列出来,参见(《亿级流量架构系列专栏总结》)。 不过很多同学看了之后,后台反馈说文章太烧脑,看的云里雾里。其实这个也正常,文章承载的信息毕竟有限,而架构的东西细节太多,想要仅仅通过文章看懂一个系统架构的设计和落地,确实难度不小。 所以接下来用大白话跟大家聊点轻松的话题,比较易于理解,而且对大家工作和面试都很有帮助。 二、场景引入,问题初现 很多同学出去面试,都

q309572960的博客 231

Java面试问题之 volatile 关键字到底是什么?

上周出去面试的小伙伴,被问到⼀个问题:说说你对 volatile 的理解?因为他之前并没关注这个知识点,网上找了一下,发现还是不清楚,于是回来问我。其实,还是有很多小伙伴都知道 vola...

JAVA高级架构 260

⼤⽩话聊聊 Java 并发⾯试问题之 volatile 到底是什么?

⼀、写在前⾯ 前段时间把⼏年前带过的⼀个项⽬架构演进的过程整理了⼀个系列出来,参⻅(《亿级流量架 构系列专栏总结》)。 不过很多同学看了之后,后台反馈说⽂章太烧脑,看的云⾥雾⾥。其实这个也正常,⽂章承载 的信息毕竟有限,⽽架构的东⻄细节太多,想要仅仅通过⽂章看懂⼀个系统架构的设计和落 地,确实难度不⼩。 所以接下来⽤⼤⽩话跟⼤家聊点轻松的话题,⽐较易于理解,⽽且对⼤家⼯作和⾯试都很有帮 助。 ⼆、场景引⼊,问题初现 很多同学出去⾯试,都会被问到⼀个常⻅的问题:说说你对vo...

ru_yuan_class的博客 361

java中volatile的含义_Java中volatile的几个问题?

要想更好的理解volatile关键字,我们先来聊聊基于高速缓存的存储交互:我们知道程序中进行计算的变量是存储在内存中的,而处理器的计算速度和内存的读取速度完全不在一个量级,区别犹如兰博基尼和自行车。要让兰博基尼开一小段就停下来等会自行车显然不太合适,所以在处理器和内存之间加了一个高速缓存,高速缓存速度远高于内存,犹如奔驰,虽然和兰博基尼还有一定差距,每个处理器都对应一个高速缓存。当要对一个变量进行...

weixin_35610224的博客 153

来说说 Java Volatile 关键字

简介 在并发编程中 Volatile 是一个很重要的关键词,那 Ta 到底是个什么个啥玩意呢? The Java volatile keyword is used to mark a Java variable as “being stored in main memory”. More precisely that means, that every read of a volatile variable will be read from the computer’s main memory, and

cab5的博客 254

深入理解volatile底层原理

一、前言 之前我们学习过synchronized,知道它是一个重量级的锁,虽然jdk1.6对其做了很大的优化,但是成本还是较高。因此Java另一个关键字闪亮登场——volatile。volatile又被称为轻量级的synchronized,它在多处理器中保证了共享变量的可见性。volatile变量修饰符如果使用恰当的话,它比synchronized的使用和执行成本会更低。下面我们将深入剖析volatile的实现原理。 二、什么是volatile Java语言规范第3版中对volatile的定义如下 Jav

weixin_41951205的博客 4451

谈谈java中的volatile

谈谈java中的volatile volatile是面试官常问的一个知识点,不过咱们把volatile全面了解一点儿,不管他怎么问,也能答出来,即使不是太完美,但是也避免了只知皮毛的尴尬!下面一步步的讲解一下。 计算机内存模型是什么? 主内存:数据存储的区域 cpu:电脑的大脑,运行速度贼鸡儿快,快就快吧,而且发展还贼鸡儿快,什么I7,I9,8线程,16线程的,越来越快,这研发速度甩了内存,硬盘好...

weixin_44130081的博客 303

volatile到底是什么?

这就导致,线程1和线程2其实都是在操作一个变量data,但是线程1修改了data变量的值之后,线程2是看不到的,一直都是看到自己本地工作内存中的一个旧的副本的值!举个例子,比如说有两个线程,他们的代码里都需要读取data这个变量的值,那么他们都会从主内存里加载data变量的值到自己的工作内存,然后才可以使用那个值。这可尴尬了,那接下来,在线程1的代码运行过程中,他可以直接读到data最新的值是1,但是线程2的代码运行过程中读到的data的值还是0!因为线程运行的代码对应的是一些指令,是由CPU执行的!

m0_53284765的博客 140
上一篇: Spring Boot快速接入Prometheus监控|写给Java开发运维
下一篇: 分布式事务(Seata)原理 详解篇,建议收藏
程序员职业指南
博客等级 码龄4年 2136粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值