面试官:我记得上一次已经问过了为什么要有Java内存模型

面试官:我记得你的最终答案是:Java为了屏蔽硬件和操作系统访问内存的各种差异,提出了「Java内存模型」的规范,保证了Java程序在各种平台下对内存的访问都能得到一致效果

候选者:嗯,对的

面试官要不,你今天再来讲讲Java内存模型这里边的内容呗?

候选者:嗯,在讲之前还是得强调下:Java内存模型它是一种「规范」,Java虚拟机会实现这个规范。

候选者:Java内存模型主要的内容,我个人觉得有以下几块吧

候选者:1. Java内存模型的抽象结构

候选者:2. happen-before规则

候选者:3.对volatile内存语义的探讨(这块我后面再好好解释)

面试官那要不你就从第一点开始呗?先聊下Java内存模型的抽象结构?

候选者:嗯。Java内存模型定义了:Java线程对内存数据进行交互的规范。

候选者:线程之间的「共享变量」存储在「主内存」中,每个线程都有自己私有的「本地内存」,「本地内存」存储了该线程以读/写共享变量的副本。

候选者:本地内存是Java内存模型的抽象概念,并不是真实存在的。

候选者:顺便画个图吧,看完图就懂了。

候选者:Java内存模型规定了:线程对变量的所有操作都必须在「本地内存」进行,「不能直接读写主内存」的变量

候选者:Java内存模型定义了8种操作来完成「变量如何从主内存到本地内存,以及变量如何从本地内存到主内存」

候选者:分别是read/load/use/assign/store/write/lock/unlock操作

候选者:看着8个操作很多,对变量的一次读写就涵盖了这些操作了,我再画个图给你讲讲

候选者:懂了吧?无非就是读写用到了各个操作(:

面试官懂了,很简单,接下来说什么是happen-before吧?

候选者:嗯,好的(:

候选者:按我的理解下,happen-before实际上也是一套「规则」。Java内存模型定义了这套规则,目的是为了阐述「操作之间」的内存「可见性」

候选者:从上次讲述「指令重排」就提到了,在CPU和编译器层面上都有指令重排的问题。

候选者:指令重排虽然是能提高运行的效率,但在并发编程中,我们在兼顾「效率」的前提下,还希望「程序结果」能由我们掌控的。

候选者:说白了就是:在某些重要的场景下,这一组操作都不能进行重排序,「前面一个操作的结果对后续操作必须是可见的」。

面试官:嗯...

候选者:于是,Java内存模型就提出了happen-before这套规则,规则总共有8条

候选者:比如传递性、volatile变量规则、程序顺序规则、监视器锁的规则...(具体看规则的含义就好了,这块不难)

候选者:只要记住,有了happen-before这些规则。我们写的代码只要在这些规则下,前一个操作的结果对后续操作是可见的,是不会发生重排序的。

面试官:我明白你的意思了

面试官那最后说下volatile?

候选者:嗯,volatile是Java的一个关键字

候选者:为什么讲Java内存模型往往就会讲到volatile这个关键字呢,我觉得主要是它的特性:可见性和有序性(禁止重排序)

候选者:Java内存模型这个规范,很大程度下就是为了解决可见性和有序性的问题。

面试官那你来讲讲它的原理吧,volatile这个关键字是怎么做到可见性和有序性的

候选者:Java内存模型为了实现volatile有序性和可见性,定义了4种内存屏障的「规范」,分别是LoadLoad/LoadStore/StoreLoad/StoreStore

候选者:回到volatile上,说白了,就是在volatile「前后」加上「内存屏障」,使得编译器和CPU无法进行重排序,致使有序,并且写volatile变量对其他线程可见。

候选者:Java内存模型定义了规范,那Java虚拟机就得实现啊,是不是?

面试官:嗯...

候选者:之前看过Hotspot虚拟机的实现,在「汇编」层面上实际是通过Lock前缀指令来实现的,而不是各种fence指令(主要原因就是简便。因为大部分平台都支持lock指令,而fence指令是x86平台的)。

候选者:lock指令能保证:禁止CPU和编译器的重排序(保证了有序性)、保证CPU写核心的指令可以立即生效且其他核心的缓存数据失效(保证了可见性)。

面试官那你提到这了,我想问问volatile和MESI协议是啥关系?

候选者:它们没有直接的关联。

候选者:Java内存模型关注的是编程语言层面上,它是高维度的抽象。MESI是CPU缓存一致性协议,不同的CPU架构都不一样,可能有的CPU压根就没用MESI协议...

候选者:只不过MESI名声大,大家就都拿他来举例子了。而MESI可能只是在「特定的场景下」为实现volatile的可见性/有序性而使用到的一部分罢了(:

面试官:嗯...

候选者:为了让Java程序员屏蔽上面这些底层知识,快速地入门使用volatile变量

候选者:Java内存模型的happen-before规则中就有对volatile变量规则的定义

候选者:这条规则的内容其实就是:对一个 volatile 变量的写操作相对于后续对这个 volatile 变量的读操作可见

候选者:它通过happen-before规则来规定:只要变量声明了volatile 关键字,写后再读,读必须可见写的值。(可见性、有序性)

面试官:嗯...了解了

本文总结

  • 为什么存在Java内存模型:Java为了屏蔽硬件和操作系统访问内存的各种差异,提出了「Java内存模型」的规范,保证了Java程序在各种平台下对内存的访问都能得到一致效果

  • Java内存模型抽象结构:线程之间的「共享变量」存储在「主内存」中,每个线程都有自己私有的「本地内存」,「本地内存」存储了该线程以读/写共享变量的副本。线程对变量的所有操作都必须在「本地内存」进行,而「不能直接读写主内存」的变量

  • happen-before规则:Java内存模型规定在某些场景下(一共8条),前面一个操作的结果对后续操作必须是可见的。这8条规则成为happen-before规则

  • volatile:volatile是Java的关键字,修饰的变量是可见性且有序的(不会被重排序)。可见性由happen-before规则完成,有序性由Java内存模型定义的「内存屏障」完成,实际HotSpot虚拟机实现Java内存模型规范,汇编底层通过Lock指令来实现。

欢迎关注我的微信公众号【Java3y】来聊聊Java面试,对线面试官系列持续更新中!

【对线面试官-移动端】系列 一周两篇持续更新中!

【对线面试官-电脑端】系列 一周两篇持续更新中!

原创不易!!求三连!!

深入浅出Java内存模型的更多相关文章

  1. 【Java并发基础】Java内存模型解决有序性和可见性

    前言 解决并发编程中的可见性和有序性问题最直接的方法就是禁用CPU缓存和编译器的优化.但是,禁用这两者又会影响程序性能.于是我们要做的是按需禁用CPU缓存和编译器的优化. 如何按需禁用CPU缓存和编译 ...

  2. JVM学习(3)——总结Java内存模型

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 为什么学习Java的内存模式 缓存一致性问题 什么是内存模型 JMM(Java Memory Model)简 ...

  3. 浅析java内存模型--JMM(Java Memory Model)

    在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步? 在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的. 线程之间通过共享程序公共的状态,通 ...

  4. JMM(java内存模型)

    What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...

  5. 《深入理解Java内存模型》读书总结

    概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...

  6. Java内存模型深度解析:final--转

    原文地址:http://www.codeceo.com/article/java-memory-6.html 与前面介绍的锁和Volatile相比较,对final域的读和写更像是普通的变量访问.对于f ...

  7. Java内存模型深度解析:volatile--转

    原文地址:http://www.codeceo.com/article/java-memory-4.html Volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特 ...

  8. Java内存模型深度解析:顺序一致性--转

    原文地址:http://www.codeceo.com/article/java-memory-3.html 数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数据 ...

  9. Java内存模型深度解析:基础部分--转

    原文地址:http://www.codeceo.com/article/java-memory-1.html 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何 ...

随机推荐

  1. BeanFactory和ApplicationContext对比

    一.BeanFactory和ApplicationContext对比 其中,ApplicationContext容器即时加载,就是一加载配置文件,就会创建对象,且自动装配bean(即写道xml中bea ...

  2. NOIP模拟51

    樱花满地集于我心,楪舞纷飞祈愿相随 前言 太菜了,人手切掉两个题,我竟然一道都不会.. 改 T3 的时候整个人的心态都崩掉了,一部分原因可能是语文素养不高导致我看不懂题解. 另一部分可能就是系太不太好 ...

  3. Java优化if-else代码

    前言 开发系统一些状态,比如订单状态:数据库存储是数字或字母,但是需要显示中文或英文,一般用到if-else代码判断,但这种判断可读性比较差,也会影响后期维护,也比较容易出现bug.比如: 假设状态对 ...

  4. excel中快速删除空白行/区域

    选中要删除的空白所在的列 按Ctrl+G 选择空值 右键->删除->整行

  5. djang2.1教育平台02

    在次申明,之所以重做这个资料是因为原幕课教程漏洞太多,新手根本没有办法正常照些学习,我凭着老男孩python 课程基础,重做这个教程 ,更改版本为当前最新版本,为了方法以后的人学习,并不是照着原文照  ...

  6. 学习PHP中的信息格式化操作

    在国际化组件的学习过程中,我们已经接触过了 NumberFormatter 这种数字的格式化操作,它可以让我们将数字转换成标准格式.货币.本地语言等形式.今天我们来学习的是另一种专门用于信息格式化的类 ...

  7. python的列表和java的数组有何异同

    今天面试被问到,自己学习一下. python的列表是可变长的,定义时不需要指定长度:pyhton是弱对象类型,python的列表存储的数据类型可以不相同:python的列表更加灵活,如可以通过''命令 ...

  8. 🧚‍♂️全套Java教程_Java基础入门教程,零基础小白自学Java必备教程👨‍💻004 # 第四单元 流程控制语句上 #

    一.本单元知识点概述 二.本单元目标 (Ⅰ)重点知识目标 1.if语句的格式及执行流程2.switch语句的格式及执行流程 (Ⅱ)能力目标 1.掌握if语句的格式及执行流程2.掌握switch语句的格 ...

  9. HTML 网页开发、CSS 基础语法—— 一. HTML概述(了解网页)

    1. 网页的本质 ① HTML就是用来制作网页文件的. ② 浏览器查看的网页都是.html或.htm文件. ③ HTML叫做超文本标记语言(Hypertext Markup Language),用于搭 ...

  10. P6085-[JSOI2013]吃货JYY【状压dp,欧拉回路】

    正题 题目链接:https://www.luogu.com.cn/problem/P6085 题目大意 \(n\)个点的一张无向图,有\(k\)条必走边,\(m\)条其他边,求从\(1\)出发经过必走 ...