内存模型

物理机的内存模型

JMM内存模型(虚拟的)

为什么要有这么多CPU缓存

因为CPU处理指令的性能很高,而CPU直接从内存中读取数据的性能相对来说就很慢了,所以如果直接都从内存中读取数据,会严重拖慢PC的处理速度.所以才会有CPU缓存,一般都是3级缓存,级别越高CPU读取性能越高,CPU内存也有寄存器,它的读取性能是最高的.

java虚拟机(JIT编译器)会对字节码指令做重排序,目的是为了提升字节码指令的执行性能.在单线程的执行情况下,指令重排序是不会影响数据结果的正确性的.但是在多线程的情况下,指令重排序就可能会影响计算结果的正确性.

为了解决以上两点,就可以使用java的volatile关键字来修饰成员变量,来保证该变量读取或写入的时候直接刷新PC的主存,读取变量的字节码指令前加入读取屏障,保证读取变量以及之后的字节码指令的有序性.写入变量的字节码指令之后加入写屏障,保证写入变量以及之前的字节码指令的有序性.(注意volatile在多线程读写计算变量的时候也不能保证结果的正确性,这个使用需要使用锁(如synchronized)来进行同步,从而保证字节码指令执行的原子性)

适用场景:

1.多线程下状态的标量检查

2.多线程下状态的双重检查(单例模式)

不适用场景:

1.该变量的写操作依赖于变量的当前值

2.该变量包含在具有其他变量的不变式中(a>b和a<b并发判断检查的场景)

final关键字可以保证两个重排序原则(JSR133):

1.在构造函数中对一个final对象的写入,与后面的把构造对象的应用赋值给引用对象,这两个操作不得重排序

2.初次读取包含一个final对象的引用,和初次读取这个final对象,这两个操作不得重排序

保证对象在初始化的时候,对象里面final修饰的对象已经被写入了.

保证读取final修饰的属性对象时,封装该属性对象的对象已经被初始化了.

注意:但如果构造方法中存在封装对象的引用逃逸,则可能存在获取不到该final修饰的属性.

参考博客:

https://www.cnblogs.com/blueSkyline/p/8858462.html