(1)什么是内存模型
究竟什么是内存模型?内存模型描述了程序中各个变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节,对象最终是存储在内存里面的,这点没有错,但是编译器、运行库、处理器 或者系统缓存 可以有特权在变量指定内存位置存储或者取出变量的值。【JMM 】(Java Memory Model的缩写) 允许编译器和缓存以数据在处理器特定的缓存(或寄存器)和主存之间移动的次序拥有重要的特权,除非程序员使用了final 或synchronized 明确请求了某些可见性的保证。
(2)内存模型的特征
a, Visibility 可见性 (多核,多线程间数据的共享)
b, Ordering 有序性 (对内存进行的操作应该是有序的)
c, Atomicity 原子性
(3)java 内存模型 ( java memory model 简称JMM)
JMM主要是为了规定了线程和内存之间的一些关系,如图所示存在一个主内存(Main Memory),Java中所有的变量存储在主内存中,对于所有的线程是共享的。每个线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中变量的拷贝,工作内存由缓存和堆栈组成,其中缓存保存的是主存中的变量的copy,堆栈保存的是线程局部变量。线程对所有变量的操作都是在工作内存中进行的,线程之间无法直接互相访问工作内存,变量的值的变化的传递需要主存来完成。在JMM中通过并发线程修改的变量值,必须通过线程变量同步到主存后,其他线程才能访问到。
Java语言规范(JLS)中对线程和主存互操作定义了6个行为,分别为read,load,use,assign,store 和 write,这些操作行为具有原子性,且相互依赖,有明确的调用先后顺序。大体上来讲,线程对某个变量的操作可以简化成下面的步骤:
1.从主内存中复制数据到工作内存 (read and load)
2.执行代码,对数据进行各种操作和计算 (use and assign)
3.把操作后的变量值重新写回主内存中 (store and write)
当然这样的运行顺序也是我们所期望的!但是, JVM并不保证第1步和第3步会严格按照上述次序立即执行。因为根据java语言规范的规定,线程的工作内存和主存间的数据交换是松耦合的,什么时候需要刷新工作内存或者什么时候更新主存的内容,可以由具体的虚拟机实现自行决定。由于JVM可以对特征代码进行调优,也就改变了某些运行步骤的次序的颠倒,那么每次线程调用变量时是直接取自己的工作存储器中的值还是先从主存储器copy再取是没有保证的,任何一种情况都可能发生。同样的,线程改变变量的值之后,是否马上写回到主存储器上也是不可保证的,也许马上写,也许过一段时间再写。那么,在多线程的应用场景下就会出现问题了,多个线程同时访问同一个代码块,很有可能某个线程已经改变了某变量的值,当然现在的改变仅仅是局限于工作内存中的改变,此时JVM并不能保证将改变后的值立马写到主内存中去,也就意味着有可能其他线程不能立马得到改变后的值,依然在旧的变量上进行各种操作和运算,最终导致不可预料的结果。