- JVM: 进程运行时将数据分区域存储,强调对内存空间的划分,即运行时数据区(Runtime Data Area)。
- JMM:内存模型是定义了线程和主内存之间的抽象关系,即 JMM 定义了 JVM 在计算机内存(RAM)中的工作方式.
通俗的讲就是,JMM是java如何管理线程跟我们的内存进行工作的方式.JVM的主要目的是把内存划分了多个区域比如堆,栈.两者不是一个层次的东西cuiyaonan2000@163.com
参考资料:
- java内存模型_百度百科
- Java 内存模型(Java Memory Model)_一起努力啊啊啊啊的博客-CSDN博客_java内存模型
计算机在高速的 CPU 和相对低速的存储设备之间使用高速缓存,作为内存和处理器之间的缓冲。将运算需要使用到的数据复制到缓存中,让运算能快速运行,当运算结束后再从缓存同步回内存之中。
在多处理器的系统中(或者单处理器多核的系统),每个处理器内核都有自己的高速缓存,它们有共享同一主内存(Main Memory)。当多个处理器的运算任务都涉及同一块主内存区域时,将可能导致各自的缓存数据不一致。
为此,需要各个处理器访问缓存时都遵循一些协议,在读写时要根据协议进行操作,来维护缓存的一致性。
如上引出了JMM,即JMM如何来管理多线程,并发线程是如何进行通信的.以及如何让他们遵守一定的规则,来操作同一块主内存cuiyaonan2000@163.com
Java 内存模型再具体点讲JMM的主要任务是(解决多线程之间数据同步,共享,传递等问题):
JMM 是共享内存的并发模型,线程之间主要通过读-写共享变量(堆内存中的实例域,静态域和数组元素)来完成隐式通信。JMM 控制 Java 线程之间的通信,决定一个线程对共享变量的写入何时对另一个线程可见。
Java 内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。
这里的工作内存是 JMM 的一个抽象概念,也叫本地内存,其存储了该线程以读/写共享变量的副本。就像每个处理器内核拥有私有的高速缓存,JMM 中每个线程拥有私有的本地内存。
不同线程之间无法直接访问对方工作内存中的变量,
线程同步的方式有2种
- 信息传递
- 共享内存(Java 线程间的通信采用的是共享内存方式)
借此引入了volatile用于解决高速缓存与主内存之间的问题.
volatile具有可见性,有序性,但是没有原子性.
- 可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值.关于实现可见性,主要是通过 Lock前缀指令 + MESI缓存一致性协议来实现的。对volatiile修饰的变量执行写操作时,JVM会发送一个Lock前缀指令给CPU,CPU在执行完写操作后,会立即将新值刷新到内存,同时因为MESI缓存一致性协议,其他各个CPU都会对总线嗅探,看自己本地缓存中的数据是否被别人修改,如果发现修改了,会把自己本地缓存的数据过期掉。然后这个CPU里的线程在读取改变量时,就会从主内存里加载最新的值了,这样就保证了可见性。各位看官还可以参考这篇文章CPU是如何通过缓存一致性MESI协议来解决可见性的
- 有序性:主要通过对volatile修饰的变量的读写操作前后加上各种特定的内存屏障来禁止指令重排序来保障有序性的。因为cpu的指令执行都是随机的,这里使用volatile修饰一个变量,让cpu的指令不要在动态的随机排序,如此可以让volatile修饰的属性的读和写操作不会被cpu打乱.
volatile 能够保证每个线程在使用或者说取 volatile修饰的属性时,必须去判断该属性是否为最新的,如果不为新的,则立即从主内存中获取.
原型问题主要出在给volatile 修饰的属性赋值的情况下. 因为在给volatile 修饰的属性赋值时,不会去检查该属性是否已经过期.