面试官:你说你精通Java并发,给我讲讲 volatile

简介: 大家好,我是指北君。PS:最近又赶上跳槽的高峰期,好多粉丝,都问我要有没有最新面试题,我连日加班好多天,终于整理好了,16000+ 道,295多份,多份面试题大全,我会持续更新中,马上就会整理更多!【文末有领取方式】今天来了解一下面试题:你对 volatile 了解多少。要了解 volatile 关键字,就得从 Java 内存模型开始。最后到 volatile 的原理。

一、Java 内存模型 (JMM)

大家都知道 Java 程序可以做到一次编写然后到处运行。这个功劳要归功于 Java 虚拟机。Java 虚拟机中定义了一种 Jva 内存模型(JMM),用来屏蔽掉各种硬件和操作系统之间内存访问差异,让 Java 程序可以在各个平台中访问变量达到相同的效果。

JMM 的主要目标是定义了程序中变量的访问规则,就是内存中存放和读取变量的一些底层的细节。

JMM 规则

  1. 变量包含实例字段,静态字段,构成数组对象的元素,不包含局部变量和方法参数。
  2. 变量都存储在主内存上。
  3. 每个线程在 CPU 中都有自己的工作内存,工作内存保存了被该线程使用到的变量的主内存副本拷贝。
  4. 线程对变量的所有操作都只能在工作内存,不能直接读写主内存的变量。
  5. 不同线程之间无法之间访问对方工作内存中的变量。

53.jpg

定义一个静态变量: static int a = 1;


54.png

上面的一系列内存操作,在 JMM 中定义了 8 种操作来完成。

JMM 交互

主内存和工作内存之间的交互,JMM 定义了 8 种操作来完成,每个操作都是原子性的。

  1. lock (锁定): 作用于主内存变量,把一个变量标识为一条内存独占的状态。
  2. unlock (解锁): 作用于主内存变量,把 lock 状态的变量释放出来,释放出来后才能被其他线程锁定。
  3. read (读取): 作用于主内存变量,把一个变量的值从主内存传输到工作内存中。
  4. load (载入): 作用于工作内存变量,把 read 操作的变量放入到工作内存副本中。
  5. use (使用): 作用于工作内存变量,把工作内存中的变量的值传递给执行引擎,每当虚拟机遇到需要这个变量的值的字节码指令时都执行这个操作。
  6. assgin (赋值): 作用于工作内存变量,把从执行引擎收到的值赋值给工作内存变量,每当虚拟机遇到需要赋值变量的值的字节码指令时都执行这个操作。
  7. store (存储): 作用于工作内存变量,把工作内存中的一个变量值,传送到主内存。
  8. write (写入): 作用于主内存变量,把 store 操作的从工作内存取到的变量写入主内存变量中。



55.jpg

从上图中可知,JMM 交互在一条线程中是不会出现任何的问题。但是当有两条线程的时候,线程 1 已经修改了变量的值,但是并未刷新到主内存时,如果此时线程 2 读取变量得到的值并不是线程 1 修改过的数据。

当引入线程 2 的时候 定义一个静态变量: static int a = 1;

56.png

下面就可以用 volatile 关键字解决问题。


二、volatile


volatile 可以保证变量对所有线程可见,一条线程修改的值,其他线程对新值可以立即得知。还可以禁止指令的重排序。


可见性

修改内存变量后立刻同步到主内存中,其他的线程立刻得知得益于 Java 的先行发生原则

先行发生原则中的 volatile 原则:一个 volatile 变量的写操作先行于后面发生的这个变量的读操作

定义一个静态变量: static int a = 1;

57.png



可见性原理

对 volatile 修饰的变量,在执行写操作的时候会多出一条 lock 前缀的指令。JVM 将 lock 前缀指令发送给 CPU ,CPU 处理写操作后将最后的值立刻写回主内存,因为有 MESI 缓存一致性协议保证了各个 CPU 的缓存是一致的,所以各个 CPU 缓存都会对总线进行嗅探,本地缓存中的数据是否被别的线程修改了。

如果别的线程修改了共享变量的数据,那么 CPU 就会将本地缓存的变量数据过期掉,然后这个 CPU 上执行的线程在读取共享变量的时候,就会从主内存重新加载最新的数据。

原子性

volatile 并不保证变量具有原子性。58.png这段代码的结果有可能不是 100000,有可能小于 100000。因为 num++ 并不是原子性的。

有序性

volatile 是通过禁止指令重排序来保证有序性。为了优化程序的执行效率 JVM 在编译 Java 代码的时候或者 CPU 在执行 JVM 字节码的时候,不影响最终结果的前提下会对指令进行重新排序。

编译器会根据以下策略将内存屏障插入到指令中,禁止重排序:

  1. 在 volatile 写操作之前插入 StoreStore 屏障。禁止和 StoreStore 屏障之前的普通写操作不会进行重排序。
  2. 在 volatile 写操作之后插入 StoreLoad 屏障。禁止和 StoreLoad 屏障之后的 volatile 读写重排序。
  3. 在 volatile 读操作之后插入 LoadLoad 屏障。禁止和 LoadLoad 之后的普通读和 volatile 读重排序。
  4. 在 volatile 写操作之后插入 LoadStore 屏障。禁止和 LoadStore 屏障之后的普通写操作重排序。

总结

面试被问到 volatile 的时候,可以从 Java 内存模型到原子性、有序性、可见性,最后到 volatile 的原理:内存屏障和 lock 前缀指令。

我是指北君,操千曲而后晓声,观千剑而后识器。感谢各位人才的:点赞、收藏和评论,我们下期更精彩!

面试大全包括:包括 Java 集合、JVM、多线程、并发编程、设计模式、SpringBoot、SpringCloud、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!

领取方式:扫描下方公众号【Java技术指北】回复【006】即可获取


59.jpg

相关文章
|
2月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
90 4
|
2月前
|
缓存 安全 Java
如何理解Java中的并发?
Java并发指多任务交替执行,提升资源利用率与响应速度。通过线程实现,涉及线程安全、可见性、原子性等问题,需用synchronized、volatile、线程池及并发工具类解决,是高并发系统开发的关键基础。(238字)
241 5
|
5月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
375 83
|
5月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
347 83
|
8月前
|
消息中间件 算法 安全
JUC并发—1.Java集合包底层源码剖析
本文主要对JDK中的集合包源码进行了剖析。
|
7月前
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
248 0
|
7月前
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
282 0
|
5月前
|
SQL 缓存 安全
深度理解 Java 内存模型:从并发基石到实践应用
本文深入解析 Java 内存模型(JMM),涵盖其在并发编程中的核心作用与实践应用。内容包括 JMM 解决的可见性、原子性和有序性问题,线程与内存的交互机制,volatile、synchronized 和 happens-before 等关键机制的使用,以及在单例模式、线程通信等场景中的实战案例。同时,还介绍了常见并发 Bug 的排查与解决方案,帮助开发者写出高效、线程安全的 Java 程序。
268 0
|
6月前
|
Java 物联网 数据处理
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%
Java Solon v3.2.0 是一款性能卓越的后端开发框架,新版本并发性能提升700%,内存占用节省50%。本文将从核心特性(如事件驱动模型与内存优化)、技术方案示例(Web应用搭建与数据库集成)到实际应用案例(电商平台与物联网平台)全面解析其优势与使用方法。通过简单代码示例和真实场景展示,帮助开发者快速掌握并应用于项目中,大幅提升系统性能与资源利用率。
202 6
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%