Java内存模型是什么?为什么Java官方要引入Java内存模型?
JMM
我们平时所使用的硬件和操作系统可能是不同的,这导致了相同的代码在不同的环境上执行会产生不同的结果。Java官方为了屏蔽掉硬件不同和os不同所带来的访问内存差异,引入了Java内存模型——JMM,从而实现Java程序在全平台一致的并发效果
Java内存模型规定,所有的成员变量(实例变量和静态变量)都保存在主内存中,但线程不能直接对主内存中的变量进行操作
每个线程都有自己的工作内存,如果线程需要操作共享数据,需要先将数据从主内存读取并copy到自己的工作内存中,然后再对工作内存中的副本进行操作
不同线程之间是不可见的,即线程A无法访问线程B的工作内存。如果线程之间需要进行变量值的传递,需要经过主内存来完成
注意:Java内存模型和JVM内存结构是两个截然不同的概念,如果我们一定要去类比的话,主内存对应堆内存中的对象实例数据部分,线程工作内存对应虚拟机栈中的部分区域
由JMM引申出的八种操作
JMM定义了什么
开篇我们提过,JMM的引入目的就是为了屏蔽掉硬件和OS不同所带来的内存访问差异,从而使得Java程序在全平台都拥有相同的并发性能。Java并发编程的基础:原子性、可见性、有序性,这三个特点,也是JMM的核心特征
原子性
一个操作时不可分割的、不会被打断的。一个线程在执行时不会被其它线程打断
可见性
当一个线程修改了共享变量的值后,其它线程立刻知道该共享变量被修改了,这就是可见性。Java为我们提供了volatile关键字来实现可见性,被volatile修饰的变量被修改后,该变量会被立刻刷新到主内存中,当其它线程需要修改该变量时,必须从主内存中获取该变量最新的值。普通变量是不能保证每次都走上述流程的
当然,除了volatile之外,final和synchronized也可以实现可见性
final关键字修饰的变量,一旦初始化完成,且没有对象逸出,那么对于其它线程就是可见的
synchronized修饰的代码,执行完后,进入unlock前,必须要将共享变量同步到主内存中
有序性
synchronized和volatile都可以实现有序性
synchronized保证有序性的原理是:一个线程lock后,必须进行unlock操作;然后其它线程才可以lock,这就保证了synchronized修饰的代码在多线程环境下是串行执行的
volatile则是通过内存屏障来禁止指令重排序,从而保证有序性