脚本宝典收集整理的这篇文章主要介绍了JMM——Java内存模型,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。@H_512_0@
内存模型(Memory Model)描述了多个线程之间通过内存交互的规范,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致。在现代的多处理器(多核处理器)系统中,处理器拥有多级缓存以提升内存访问速度同时减少了内存总线的访问量。变量最终会保存在内存中,但是编译器、运行时、处理器可以对指令优化和重新排序,缓存、寄存器也对内存进行了读写优化,只要保证在单个线程内行为与代码顺序串行语义相同即可。内存模型定义了充分且必要的条款,描述了程序中变量之间的关系,以及变量的读取、写入的底层细节,实现了并发过程中的原子性、可见性、有序性。
原始的Java内存模型存在一些不足,因此Java内存模型在Java 1.5时被重新修订(JSR133)。这个版本的Java内存模型在Java 8中仍然在使用。老版本中的问题有:
volatile语义增强:volatile字段的读、写操作与其它任务内存操作操作重排序,volatile的读操作与监视器锁的获取具有相同的内存语义(缓存失效并从主存重新读取),volatile的定操作与监视器锁的释放具有相同的内存语义(缓存刷入主存)。在这个约定下,线程A写入volatile字段V后,线程B可以读出V的值,同时线程A在写入V时能够看到的变量值对线程B也可见。
是否可以重排序 | 第二个操作 | 第二个操作 | 第二个操作 |
---|---|---|---|
第一个操作 | 普通读/普通写 | volatile读/monITor enter | volatile写/monitor exit |
普通读/普通写 | No | ||
voaltile读/monitor enter | No | No | No |
volatile写/monitor exit | No | No |
其中普通读指getfield, getstatic, 非volatile数组的arrayload, 普通写指putfield, putstatic, 非volatile数组的arrayStore。volatile读写分别是volatile字段的getfield, getstatic和putfield, putstatic。monitorenter是进入同步块或同步方法,monitorexist指退出同步块或同步方法。
final字段增强:只要对象正确构造,那么不需要使用同步就可以保证任意线程都能看到final字段在构造器中被初始化之后的值。编译器会在final域的写之后,构造器函数return之前,插入StoreStore屏障。这个屏障禁止处理器把final域的写重排序到构造函数之外。写final域的重排序规则可以保证:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域不具有这个保障。读final域的重排序规则是,禁止处理器重排序初次读取对象引用与初次读取该对象包含的final域这两个操作。编译器会在读final域操作的前面插入一个LoadLoad屏障。读final域的重排序规则可以确保:在读一个对象的final域之前,一定会先读包含这个final域的对象的引用。
初次读对象引用与初次读该对象包含的final域,这两个操作之间存在间接依赖关系。由于编译器遵守间接依赖关系,因此不会重排序这两个操作;大多数处理器也会遵守间接依赖,也不会重排序这两个操作。但有少数处理器允许对存在间接依赖关系的操作做重排序(比如alpha处理器),这个规则就是专门用来针对这种处理器的。
对于引用类型,写final域的重排序规则对编译器和处理器增加了如下约束:
HappendBefore规则包括:
以上是脚本宝典为你收集整理的JMM——Java内存模型全部内容,希望文章能够帮你解决JMM——Java内存模型所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。