注意区别于 JVM 内存结构
JVM 内存结构,和 Java 虚拟机的运行时区域有关
Java 内存模型,和 Java 的并发编程有关
介绍
Java 内存模型(Java Memory Model 或 JMM)并不像 JVM 内存结构一样是真实存在的,它是一个抽象的概念。Java 的多线程之间通过共享内存进行通信,在通信过程中会存在一系列如可见性、原子性、顺序性等问题,而 JMM 就是围绕着多线程通信以及与其相关的一系列特性而建立的模型
线程 A 与线程 B 之间如要通信的话,要经历下面 2 个步骤:
- 线程 A 把本地内存A中更新过的共享变量刷新到主内存
- 线程 B 到主内存中去读取线程A之前已更新过的共享变量
从整体来看,这两个步骤实质上是线程 A 在向线程 B 发送消息,而且这个通信过程必须要经过主内存,JMM 控制主内存与每个线程的本地内存之间的交互
并发问题
-
工作内存数据一致性
各个线程操作数据时会保存使用到的主内存中的共享变量副本,当多个线程的运算任务都涉及同一个共享变量时,将导致各自的的共享变量副本不一致
-
指令重排序优化
重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境
volatile
-
保证可见性
线程写 volatile 变量的过程:
-
改变线程工作内存中 volatile 变量副本的值
-
将改变后的副本的值从工作内存刷新到主内存
线程读volatile变量的过程:
-
从主内存中读取 volatile 变量的最新值到线程的工作内存中
-
从工作内存中读取 volatile 变量的副本
但是如果多个线程同时把更新后的变量值同时刷新回主内存,可能导致得到的值不是预期结果
-
禁止指令重排序
-
当程序执行到 volatile 变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行
-
在进行指令优化时,不能将在对 volatile 变量访问的语句放在其后面执行,也不能把 volatile 变量后面的语句放到其前面执行
总结
JMM 描述了在多线程代码中,哪些行为是正确的、合法的,以及多线程之间如何进行通信,代码中变量的读写行为如何反应到内存、CPU 缓存的底层细节
JMM 中定义了关键字 volatile、final 和 synchronized 的行为,确保正确同步的 Java 代码在所有的处理器架构上都能正确执行
推荐一篇更详细的文章:理解Java内存模型