计算机在执行程序的时候,计算数据的过程是在cpu中进行计算的,而数据是放在主存当中的,也就是电脑的物理内存。
cpu每次先到主存当中取数据,然后进行计算,计算完之后,将数据再次写入到主存当中。随着cpu的执行速度越来越快,每次cpu计算完需要在主存当中操作因为内存的读取和写入速度完全不能和cpu相比,所以每次都操作内存的时候都需要等待,所以为了提高效率,在cpu和主存之间加了高速缓存。
这样,执行过程就变为执行程序的过程中,将主存中的数据复制一份到高速缓存中,当cpu进行计算的时候就可以直接到高速缓存当中取数据和写入数据,计算结束之后将告诉缓存中的数据再刷新到主存当中。
之后又有了多级缓存,当cpu需要读取数据的时候,先到一级缓存中取,没有的话再到二级缓存中拿,一直没有就到三级缓存或者主存当中取拿。在cpu和内存之间增加缓存,在多线程背景下会出现缓存不一致问题,在多核cpu下,每个核都会有主存的数据的一份拷贝,但是在计算的过程中,多核可能就会出现同一份数据的缓存不一致的结果。
在CPU和主存之间增加缓存,在多线程场景下会存在缓存一致性问题。除了这种情况,还有一种硬件问题也比较重要。那就是为了使处理器内部的运算单元能够尽量的被充分利用,处理器可能会对输入代码进行乱序执行处理。这就是处理器优化。
除了现在很多流行的处理器会对代码进行优化乱序处理,很多编程语言的编译器也会有类似的优化,比如Java虚拟机的即时编译器(JIT)也会做指令重排。
缓存一致性问题其实就是可见性问题。而处理器优化是可以导致原子性问题的。指令重排即会导致有序性问题
什么是内存模型为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操作行为的规范。通过这些规则来规范对内存的读写操作,从而保证指令执行的正确性。它与处理器有关、与缓存有关、与并发有关、与编译器也有关。他解决了CPU多级缓存、处理器优化、指令重排等导致的内存访问问题,保证了并发场景下的一致性、原子性和有序性。内存模型解决并发问题主要采用两种方式:限制处理器优化和使用内存屏障。
Java程序是需要运行在Java虚拟机上面的,Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制及规范。
java内存模型规定了所有的变量都是存储在主存当中的,线程是有独自的不共享的工作内存,工作内存中的变量存储的是这个变量在主存当中的拷贝的副本,并且不同线程是不能直接访问到工作内存中的变量,线程之间的数据的传递是通过工作内存和主存进行数据同步而来实现数据的共享的。
java内存模型规范了在多线程操作共享内存的时候,如何进行数据同步以及什么时候进行数据同步。,也就是为了解决多级缓存导致的缓存不一致性问题(可见性问题),以及硬件的处理器优化和指令重排导致的原子性和有序性问题
(主内存和工作内存与JVM内存结构中的Java堆、栈、方法区等并不是同一个层次的内存划分,无法直接类比)如果和jvm中的内存结构类比的话,我的想法是主存就相当于方法区和堆,因为都是线程可以共享的,而工作内存就相当于虚拟栈,因为是线程独有的。
-
原子性
java提供了两个高级字节码指令monitorenter和monitorexit来保证操作的原子性,关键字synchronized的实现就是使用这两个字节码指令。 -
可见性
线程在工作内存中修改了某个变量的值,然后工作内存就会将这个值同步到主存当中,其他线程的工作内存在用到这个变量的时候需要去 主存当中刷新变量值,通过这种取变量值需要依赖主存的方式保证可见性,关键字volatile可以保证可见性。 -
有序性
volatile关键字会禁止指令重排,sychronized关键字会保证同一时间只会有一个线程进行操作也可以保证有序性(不太理解)。
内容都是参照http://47.103.216.138/archives/2550这篇文章记录下来的。



