面试官:我问的是Java内存模型,你回答堆栈方法区干嘛?
听说微信搜索《Java鱼仔》会变更强哦!
本文收录于JavaStarter,里面有我完整的Java系列文章,学习或面试都可以看看哦
(一)概述
很多人会把Java内存区域(运行时数据区)和Java内存模型(JMM)搞混,这两者是完全不一样的东西。
Java内存区域是指JVM运行时数据分区域存储,而Java内存模型是定义了线程和主内存之间的抽象关系,了解Java内存模型是学好Java并发编程的基础。
(二)Java内存模型
Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。我们来看一张图:
每个线程拥有一个自己的私有工作内存,需要变量时从主内存中拷贝一份到工作内存,如果更新过变量之后再将共享变量刷新到主内存。
但是两个线程之间,是没有办法读取对方工作内存中的变量值的。看一个例子:
public class Test { private static boolean flag=false; public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { @Override public void run() { System.out.println("waiting"); while (!flag){} System.out.println("in"); } }).start(); Thread.sleep(2000); new Thread(new Runnable() { @Override public void run() { System.out.println("change flag"); flag=true; System.out.println("change success"); } }).start(); } }
首先定义了一个静态变量flag为false,A线程等待flag等于true后输出in,于是我们新开一个线程将flag修改为true。结果是A线程依旧无法输出in。
原理看Java内存模型的图就理解了,不同的线程修改变量,对本地线程是不可见的。
(三)JMM数据的原子操作
通过上面这段代码,我们已经知道了Java内存模型的结构,那么工作内存和主内存之间是如何读取变量又是如何修改变量的呢?JMM提供了对变量的一系列原子操作。我们先不讲理论,看个图,这个图描述了上面一段代码的执行过程:
整个过程一共十步,重复几个步骤不讲了,我把不重复的六个操作列一下:
read:从主内存读取数据
load:将主内存读取到的数据写入工作内存
use :从工作内存中读取数据来使用
assign:把计算好的值重新赋值到工作内存中
store:将工作内存数据写入主内存
write:将store过去的变量赋值给主内存中的变量
通过上面的图,对下面六个原子操作的理解应该可以更加深刻了。JMM的原子操作一共有八个,下面列出剩下的两个
lock:将主内存变量加锁,标识为线程独占状态
unlock:将主内存变量解锁,解锁后其他线程可以锁定该变量
(四)JMM缓存不一致问题
从前面的例子我们已经看到了,一个线程修改完数据,另外一个线程无法立即可见,这就是JMM缓存不一致的问题,有两种解决办法:
加锁:
还记得我们没有用到过的JMM原操作的最后两个吗,lock和unlock,使用这两个操作就可以实现缓存一致性,一个线程想要获取某个主内存变量时,先使用lock将主内存变量加锁,只有他才能使用,等用完后再unlock,其他线程才能竞争。但是加锁意味着性能低。
MESI缓存一致性协议:
这个协议涉及到cpu的总线嗅探机制,从上面的JMM执行的流程图中我们可以看到当某个线程修改了共享变量后,他会回写到主内存,MESI缓存一致性协议就是通过cpu的总线嗅探机制,将其他也正在使用该变量的线程的数据失效掉,使得这些线程要重新读取主内存中的值,从而保证缓存最终一致性。(volatile的实现原理)
(五)总结
Java内存模型在多并发中十分重要,包括后面学习volatile或者synchronized这个关键字的时候,都会回到这个Java内存模型中。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
数据管理流程,基础入门简介
一、基础思维 数据在现在互联网的行业中可以说是最核心的话题,数据的价值已经被称为资产了,大部分的互联网应用都会源源不断的产生各种数据,如何管理和使用这些数据,让这些看似平常的数据产生更大的价值,一直是热门的探索领域。比如常见的风控、营销、推广等各种业务,都需要依赖大量的用户行为数据作为依赖,才能精准的对相关流程做出分析判断。 数据管理是一项复杂而且庞大的工程,需要付出的时间和成本非常高,通常的说法就是对用户有效的数据进行采集,存储,分析,组建业务模型,二次业务应用,以此让数据发挥更大的价值。 在企业考虑做数据沉淀管理时候,通常这里有一个基础的考虑,数据量是否庞大,搭建起的数据管理体系能带来的收益是否能覆盖成本;对于企业来说,很多事情做起来都是对的,但是不一定是对自身发展是有益的;如果基于数据管理,能带来更多业务收益,那这个庞大的工程自然值得投入。 二、业务与数据 这里再从实际流程来看这个问题,通常一个项目在开发初期时候,为节约成本都会采取快速迭代的方式,基于产品设计和用户使用分析,不断快速升级,在这一过程中也是数据不断积累的过程,一个方向清晰的产品发展的基本过程:产品核心功能实现,丰富...
- 下一篇
大数据开发-表数据波动、码值分布波动监控
经历一番推理演算,每个字段逐字分析,接着https://blog.csdn.net/hu_lichao/article/details/110358607 前面的理论,本篇对前面的监控做了更进一步的设计产出,看完绝对不会浪费您的时间。 设计摘要: 任务执行、监控和报警从设计上是可以完全分开的,分开可以让任务执行尽可能只做任务执行的事情,监控可以根据多种监控规则来进行数据统计,数据分布,而报警则专注于如何根据监控的结果进行自定义灵活地报警。其中在设计上可以以监控为主体,任务执行和报警可以依据需求来定制,从而更好满足各方需求。 监控规则的设计,暂时从以下几个方面入手,数据分区的生成、数据分区的数据量、数据分区的数据量波动、表数据字段的码值分布波动。监控的主要职责是跑数,跑出报警需要的数据,而报警,可以根据监控的输出数据以及监控配置进行生成done文件或者undone 和 报警。 done目录和原表目录类似 表/版本/分区或日期/done/a.done or b.done or c.done (根据配置的根目录 + 表路径的后半部分来生成) 1.表数据监控 监控什么?要达到什么目的? 监控主...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品