请务必将Java内存模型与Java内存结构(堆、栈、程序计数器等)区分开!!
首先理解JMM:
在不同的操作系统中,内存的访问会有一定差异,因此需要JMM屏蔽掉各种硬件和操作系统之间的差异。让同一套Java程序能在不同操作系统中正确执行。
在Java中,所有实例域、静态域和数组元粗存储在堆内存中,堆内存在线程之间共享,因此共享变量才会有内存可见性问题。而局部变量,方法定义参数和异常处理器参数不会在线程间共享(存储在栈中),不会有类似的问题。
Java线程间通信由Java内存模型控制,JMM决定了一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来说,线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程读/写共享变量的副本。线程的工作都是对本地内存中的线程共享变量副本进行读写,而不直接对主内存中共享变量进行读写。
要注意的是,本地内存实际上并不存在,可以理解为高速缓存、写缓冲区、寄存器以及其他硬件和编译器优化的一个抽象整合。
JMM的抽象示意图如下:

由此可见,线程之间通信需要经过两个步骤:
- 线程A把本地内存中更新过的共享变量刷新到主内存
- 线程B从主内存中读取A更新过的共享变量
可以使用Volatile关键字可以保证以上两个步骤的完成。
从整体来看,JMM通过控制主内存与每个线程的本地内存之间的交互,为Java程序员提供内存可见性保证。