范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Java内存模型(JMM)详解

  #头条创作挑战赛#什么是 JMM?
  在上一篇文章https://mp.weixin.qq.com/s/ZiuZHQ8OMFudzr0jCqn1dQ中,我们了解了计算机由于各个硬件的读取速度之间的巨大差距,和充分利用CPU的性能的手段方法,及其所带来的一系列问题: 为了充分压榨CPU的性能, CPU 会对指令乱序执行或者语言的编译器会指令重排 ,让CPU一直工作不停歇,但同时会导致有序性问题。 为了平衡CPU的寄存器和内存的速度差异,计算机的CPU 增加了高速缓存,但同时导致了 可见性问题 为了平衡CPU 与 I/O 设备的速度差异,操作系统增加了进程、线程概念,以分时复用 CPU,但同时导致了原子性问题。
  Java 是最早尝试提供内存模型的编程语言。由于Java 语言是跨平台的,另外各个操作系统总存在一些差异,Java在物理机器的基础上抽象出一个 "内存模型(JMM)"
  JMM  可以看作是 Java 定义的并发编程相关的一组规范,除了抽象了线程和主内存之间的关系之外,其还规定了从 Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范,这样就可以屏蔽各个操作系统的差异,简化多线程编程。 Java 运行时内存区域与硬件内存的关系Java 内存区域和Java内存模型有何区别?
  这是一个非常容易让人混淆的问题,Java 内存区域和内存模型完全是不一样的东西, Java 内存区域, 也叫内存区域、JVM内存模型,和 Java 虚拟机(JVM)的运行时区域相关,是指 JVM运行时将数据分区域存储,强调对内存空间的划分。
  Java内存模型,也叫内存模型(JMM),是Java 定义的并发编程相关的一组规范,除了抽象了线程和主内存之间的关系之外,其还规定了从 Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范,屏蔽各个操作系统的差异。
  通俗点说: JMM规范了程序中变量的访问规则,保证了操作的原子性、可见性、有序性, 我们下文慢慢道来。
  我们知道JVM 运行时内存区域是分区域的,分为栈、堆等,其实这些都是 JVM 定义的逻辑概念。但在传统的硬件内存架构中是没有栈和堆这种概念。
  其中: 图中栈可以细分为:虚拟机栈(JVM Stacks)和本地方法栈(Native Method Stack) 虚拟机栈(JVM Stacks): 线程私有,它的生命周期和线程相同 ,描述的是Java方法执行的内存模型,每个方法在执行的同时都会创建一个线帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每个方法从调用直至执行完成的过程,都对应着一个线帧在虚拟机栈中入栈到出栈的过程
  本地方法栈(Native Method Stack): 线程私有 ,本地方法栈与虚拟机栈的作用是一样的,只不过虚拟机栈是服务Java方法的,而本地方法栈是为虚拟机调用Native方法服务的。在Java虚拟机规范中对于本地方法栈没有特殊的要求,虚拟机可以自由的实现它,因此 在Sun HotSpot虚拟机直接把本地方法栈和虚拟机栈合二为一了 。
  线程开始调用本地方法时,会进入 不再受 JVM 约束的世界。本地方法可以通过 JNI(Java Native Interface)来访问虚拟机运行时的数据区,甚至可以调用寄存器,具有和 JVM 相同的能力和权限。 JNI 类本地方法最著名的应该是 System.currentTimeMillis() 堆(Heap)
  虚拟机堆是Java虚拟机中内存最大的一块,是被 所有线程共享 的,在虚拟机启动时候创建,Java堆唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存,随着JIT编译器的发展和逃逸分析技术的逐渐成熟,栈上分配、标量替换优化的技术将会导致一些微妙的变化,所有的对象都分配在堆上渐渐变得不那么"绝对"了。
  更多精彩文章在公众号「小牛呼噜噜」
  Java中栈和堆既存在于计算机的 高速缓存 中,又存在于主存中,所以两者并没有很直接的关系。 Java 线程与主内存的关系
  Java 内存模型(JMM)  抽象了线程和主内存之间的关系,就比如说线程之间的共享变量必须存储在主内存中。 在 JDK1.2 之前,Java 的内存模型实现总是从  主存  (即共享内存)读取变量,是不需要进行特别的注意的。
  而在当前的 Java 内存模型下,线程可以把变量保存  本地内存  (比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。 什么是主内存?什么是本地内存?主内存  :所有线程创建的实例对象都存放在主内存中,不管该实例对象是成员变量还是方法中的本地变量(也称局部变量) 本地内存  :每个线程都有一个私有的本地内存来存储共享变量的副本,并且,每个线程只能访问自己的本地内存,无法访问其他线程的本地内存。本地内存是 JMM 抽象出来的一个概念,存储了主内存中的共享变量副本。
  Java 内存模型其实是一种规范,定义了很多东西: 所有的变量都存储在主内存(Main Memory)中。 每个线程都有一个私有的本地内存 (Local Memory),本地内存中存储了该线程以读/写共享变量的拷贝副本。 线程对变量的所有操作都必须在本地内存中进行,而不能直接读写主内存。 不同的线程之间无法直接访问对方本地内存中的变量。
  这里所讲的主内存、工作内存与 Java 内存区域中的 Java 堆、栈、方法区等并不是同一个层次的内存划分,这两者基本上是没有关系的,如果两者一定要勉强对应起来,那从变量、主内存、工作内存的定义来看,主内存主要对应于Java堆中的对象实例数据部分,而工作内存则对应于虚拟机栈中的部分区域。 线程间通信
  线程间的通信一般有两种方式进行,一是通过消息传递,二是共享内存。Java 线程间的通信采用的是 共享内存 方式,JMM 为共享变量提供了线程间的保障。如果两个线程都对一个共享变量进行操作,共享变量初始值为 1,每个线程都变量进行加 1,预期共享变量的值为 3。在 JMM 规范下会有一系列的操作。我们直接来看下图:
  在多线程的情况下,对主内存中的共享变量进行操作可能发生线程安全问题,比如:线程 1 和线程 2  同时 对同一个共享变量进行操作,执行+1操作,线程 1 、线程2 读取的共享变量是否是彼此修改前还是修改后的值呢,这个是无法确定的,这种情况和CPU的高速缓存与内存之间的问题非常相似
  如何实现主内存与工作内存的变量同步,为了更好的控制主内存和本地内存的交互,Java 内存模型定义了八种操作来实现: lock:锁定。作用于主内存的变量,把一个变量标识为一条线程独占状态。 unlock:解锁。作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。 read:读取。作用于主内存变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用 load:载入。作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。工作内存即本地内存。 use:使用。作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。 assign:赋值。作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。 store:存储。作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作。 write:写入。作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中。 重温Java 并发三大特性原子性
  原子性:即一个或者多个操作作为一个整体,要么全部执行,要么都不执行,并且操作在执行过程中不会被线程调度机制打断;而且这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换(context switch) 比如: int i = 0;   //语句1,原子性  i++;         //语句2,非原子性
  语句1大家一幕了然,语句2却许多人容易犯迷糊,i++其实可以分为3步: i 被从局部变量表(内存)取出, 压入操作栈(寄存器),操作栈中自增 使用栈顶值更新局部变量表(寄存器更新写入内存)
  执行上述3个步骤的时候是可以进行线程切换的,或者说是可以被另其他线程的 这3 步打断的,因此语句2不是一个原子性操作
  更多精彩文章在公众号「小牛呼噜噜」
  在 Java 中,可以借助synchronized 、各种 Lock以及各种原子类实现原子性。 synchronized和各种Lock是通过保证任一时刻只有一个线程访问该代码块,因此可以保证其原子性。各种原子类是利用CAS (compare and swap)操作(可能也会用到 volatile或者final关键字)来保证原子操作。 可见性
  可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值。 我们来看一个例子: public class VisibilityTest {     private boolean flag = true;      public void change() {         flag = false;         System.out.println(Thread.currentThread().getName() + ",已修改flag=false");     }      public void load() {         System.out.println(Thread.currentThread().getName() + ",开始执行.....");         int i = 0;         while (flag) {             i++;         }         System.out.println(Thread.currentThread().getName() + ",结束循环");     }      public static void main(String[] args) throws InterruptedException {         VisibilityTest test = new VisibilityTest();          // 线程threadA模拟数据加载场景         Thread threadA = new Thread(() -> test.load(), "threadA");         threadA.start();          // 让threadA执行一会儿         Thread.sleep(1000);         // 线程threadB 修改 共享变量flag         Thread threadB = new Thread(() -> test.change(), "threadB");         threadB.start();      } }
  threadA 负责循环,threadB负责修改 共享变量flag,如果flag=false时,threadA 会结束循环,但是上面的例子会死循环。原因是threadA无法立即读取到共享变量flag修改后的值。我们只需 private volatile boolean flag = true;加上volatile关键字threadA就可以立即退出循环了。
  Java中的volatile关键字提供了一个功能,那就是被其修饰的变量在被修改后可以立即同步到主内存,被其修饰的变量在每次是用之前都从主内存刷新。
  因此,可以使用volatile来保证多线程操作时变量的可见性。除了volatile,Java中的synchronized和final两个关键字 以及各种 Lock也可以实现可见性。 有序性
  有序性:即程序执行的顺序按照代码的先后顺序执行。 int i = 0; int j = 0; i = 10;   //语句1 j = 1;    //语句2
  但由于指令重排序问题,代码的执行顺序未必就是编写代码时候的顺序。语句可能的执行顺序如下: 语句1 语句2 语句2 语句1
  指令重排对于非原子性的操作,在不影响最终结果的情况下,其拆分成的原子操作可能会被重新排列执行顺序。 指令重排不会影响单线程的执行结果,但是会影响多线程并发执行的结果正确性 。 在Java 中,可以通过volatile关键字来禁止指令进行重排序优化,
  详情可见:https://mp.weixin.qq.com/s/6GGV0YDwTFW_4VcLRYfBAg
  也可以使用synchronized关键字保证同一时刻只允许一条线程访问程序块。
  参考资料:
  《java并发编程实战》
  https://www.cnblogs.com/czwbig/p/11127124.html
  本篇文章到这里就结束啦,如果我的文章对你有所帮助,还请帮忙一键三连: 点赞、关注、收藏 ,你的支持会激励我输出更高质量的文章,感谢!
  计算机内功、源码解析、科技故事、项目实战、面试八股等更多硬核文章,首发于公众号「小牛呼噜噜」,我们下期再见!

用苹果手机是原罪?苹果连续9天被炮轰了6次没想到吧,各位尊贵的苹果用户们,国庆假期第一天,一觉醒来莫名其妙地直接被道德绑架?前几天不知道各位有没有看到过一个经济学家发出的一篇文章,在短视频app上都有很多人搜索很多人关注。广东要求电动车充电站县县全覆盖,上汽新能源连续破十万普及新能源汽车是推动实现双碳目标的重要举措,随着技术不断成熟和突破,新能源车凭借着绿色环保舒适和出行成本低等诸多因素逐渐进入了产业化阶段消费者的认可度进一步提高。然而,除了新能源车快递员称因投诉公司要被罚5000元!申通是绩效考核罚款近日,南都记者接到重庆一名申通快递员谢先生报料,称其因某快递网点对自己的索赔要求不合理,其向当地政务服务热线反馈情况,结果因作为内部员工投诉自己的公司,被通知将面临5000元罚款。Intel为开发者提供一周的免费cloud云实例VM先看效果,cpu信息和内存信息,我申请的是最低级的TinyVM级别的虚拟机rootcloud30261catproccpuinfoprocessor0vendoridGenuine美拉拢失败,刚鼓动巴方向中国申请债务减免,巴方就择人民币结算据观察者网发布的报道称,巴基斯坦贸易协会主席扎希德近日在接受媒体采访时公开表示,目前,巴基斯坦正考虑在对俄贸易中使用人民币或者卢布结算,以取代当下的美元结算机制,并且,此项计划将会除了能源,中俄合作有了新战略布局,这已说明,两国在做最坏准备近日,中国驻俄罗斯大使张汉晖对媒体表示,面对复杂的国际环境和新冠疫情等考验,中俄经贸韧劲十足,逆势增长,从1月到8月两国贸易额已经达到1172。06亿美元,同比增长31。4。未来两2023年,农民养老金统一按1300元发放,可行吗?2023年,农民养老金统一按1300元发放,可行吗?养老金是大部分退休人员唯一的经济来源,养老金的多少直接决定了退休人员生活质量的好坏。所以养老金能否按时足额发放,并保障退休人员基套现欧洲千亿后,李嘉诚没有回中国投资,反而又从中国套现2百亿李嘉诚这波操作确实让人看不懂。李嘉诚旗下的长实集团突然宣布卖掉了香港半山的一个豪宅项目,买家是新加坡的资本,这次李嘉诚又从中国市场套现了2百亿。李嘉诚这到底是要干什么?他不是刚刚才常熟农商行副行长包剑辞任,董事会同意李勇接任北京商报讯(记者孟凡霞李海颜)9月30日,常熟农商行发布公告称,该行董事会收到包剑的书面辞职报告。包剑因工作调动,辞去该行副行长职务。辞职报告自送达该行董事会时即生效,包剑辞任后将房产中介的第三次洗牌?面临的是外部环境的变化还是自我清洗?在房住不炒主基调的影响下,加之疫情市场调控和经济下行的这几年,我坚信房产中介这个行业已经发生了很深刻的变化。其实,本质上是很多中小老板的无知和惯性思维导致的结果。我认为,业务量严重为何连续出台两个国字头房地产利好政策,现在是否可以抄底房地产不动产今天的房产政策迎来换购减免个人所得税和公积金首套房贷利率下调的两大利好政策,各大房产人中介开发商奔走相告,连续几年的房产限购限售等政策严重阻碍了不动产的流通性,使得不动产的商
为什么有些银行要收储户每月2。5元的短信费用?这样合理吗?国内银行之所以能够躺着赚钱,首先靠的是世界上最高的存贷款利息差,其次则是靠不断创新推陈出新层出不穷的服务收费。每月收2。5元的短信费用多不多?好像不多。截至2017年年末,全国借记栾川景区免费的有哪些推荐?一切向钱看的时代貌似没有免费的景区让你去吧,不过,你可以办一张洛阳的旅游年票,鸡冠洞,龙峪湾,抱犊寨,天河大峡谷,蝴蝶谷都可以用年票,可以给你省一笔不小的费用,去一两个景点就赚回来关于人性与欲望经典电影大片有哪些?西西里的美丽传说绝对有人性有欲望,经典大片。托纳多雷的寻找三部曲之一,让人似曾相识。美丽女人马琳娜是小镇上最美丽的女人,他的未婚夫是一名军官,本来能拥有个美好的生活,可是因为战争,请问大家高职扩招的全日制专科学历有啥用吗?跟某高职系书记交流了一下,扩招的目前招生已完成但是还没开学,上边突然丢下来的任务措手不及,目前具体政策不清。统招学生一学期400学时,扩招的200学时主要是周末假期完成而且包含实习流浪地球中,人们给地球装上了发动机,得需要多大的推力才能使地球脱离轨道?大气层还会有吗?多谢邀请。大家新年好!假期中似乎大家都在刷流浪地球,但笔者身体稍有不适只能等假期过后再说了。关于这个问题,看了看影评有一些了解,与大家分享。在这个故事中,地球人让地球停止转动并脱离走近科学有哪些不合常理的故事?这里我可要为人家走进科学正名,走进科学成立初期可是正儿八经的科普类节目,非常深奥,甚至请过六个诺贝尔奖获得者。结果呢,收视率惨不忍睹。为了挽救这个栏目,当时任Y视科教频道负责人张国理论上可以制造出流浪地球那样的行星发动机吗,产生的推力能推动地球离开太阳系吗?诸葛小村姑解答既然是理论上,当然可以造出流浪地球里面的行星发动机!要知道,作者刘慈欣是一名计算机工程师,他的大学物理,至少学了4年吧,这样浅显的道理,难道不明白?大伙儿质疑最多的是为什么有科学家怀疑太阳系是被设计出来的?为什么有科学家怀疑太阳系是被设计出来的?一直以来就有科学家宣称,太阳系是被超级文明设计出来的,因为在太阳系中存在的巧合实在是太多了,而这些无巧不成书的组合让地球诞生了文明,继而开始中考考了个很差的高中,现在高二,知道自己本科没有希望了,有没有什么值得文科生选的专业或专科学校?坐标辽宁省,亲身经历谈一谈吧,谨慎参考。当年我表姐家女儿学渣一个,普通高中都没有考上,自费生去的普高。念到高二,成绩垫底,本科肯定没戏,专科也是民办那种类型学校。我建议让孩子转学去地震云真的有科学依据吗?这不是地震云,地震云不是科学意义上的概念,云和地震并无关联,云不是地震前兆现象,但地震云的说法在民间长盛不衰,虽然已有气象和地震方面的专业人士进行过多次科普。地震的发生是板块运动的有些科学家预言宇宙将在一千亿年后毁灭,那个时候人类该怎么办?宙宇的存在是永恒的,处时空和形态是可变的!宇宙是永恒的。只有某星球死亡,而使这星球上万物消失。如果地球死亡了,地球上的人类会灭绝,万物也同样灭绝。传统体现神启的巫者,是千古以来,近