Java内存模型即Java Memory Model ,简称JMM。JMM定义了Java虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,JMM 隶属于JVM.
JMM 决定一个线程对共享变量的写入何时对另一个线程可见。
从抽象的角度看,JMM定义了线程和主内存之间的抽象关系:线程间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程用以读写的共享变量的副本。
本地内存是JMM 的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。
如上图,线程A 与线程B 如要通信
1)线程A把本地内存A中更新过的共享变量刷新到主内存中去
2)线程B到主内存中去读取线程A之前已更新过的共享变量
从整体性来看,这两个步骤实质上是线程A向线程B 发送消息,而且这个通讯过程必须要经过主内存。JMM 通过控制主内存与各个线程的本地内存之间的交互,来提供内存可见性保证。
Java内存模型是一个抽象概念,下面是JVM 对Javan内存模型的实现
JVM 对Java内存模型的实现
在JVM内部,Java内存模型把内存分成了两部分:线程栈区和堆区
每一个运行在Java虚拟机里的线程都拥有自己的线程栈。这个线程栈包含了这个线程调用方法当前执行点相关信息。一个线程仅能访问自己的线程栈。一个线程栈创建的本地变量对其他线程不可见,仅自己可见,即使两个线程执行同样的代码,这两个线程仍然在自己的线程栈中的代码来创建本地变量。因此每个线程拥有每个本地变量的独有版本。
所有原始类型的本地变量都存放在线程栈上,因此对其他线程是不可见的。一个线程可能向另一个线程传递一个原始类型变量的拷贝,但它不能共享这个原始类型变量自身。
堆上包含在Java程序中创建的所有对象,无论是哪个对象创建的,这包括原始类型的对象版本。如果一个对象被创建然后赋值给一个局部变量,或者用来作为另一个对象的成员变量,这个对象仍然是存放在堆上。
JMM 特性(针对JMM内部)
1)原子性
访问存储单元内的任何类型的字段的值以及对其更新操作时,除开long 类型和double类型,其他类型的字段必须保证其原子性,这些字段也包括对象服务的引用。(也可对long 和double 延伸为 volatile long 和volitile double)
2)可见性
该规则定义了一个线程在何种情况下可以访问或影响另一个线程。
当一个线程需要修改另外一个线程的可见单元时需遵守以下原则
- 一个写入线程释放的同步锁和紧随其后进行读取的读线程的同步锁是同一个
- 一旦某个字段被申明为volatile,在任何一个写入线程在工作内存刷新缓存之前需要进行进一步的内存操作(即针对这样的字段立即刷新)
- 当某个线程第一次去访问某个对象的域时,它要么初始化该对象的值,要么从其他写入线程可见域里面去读取该对象的值
- 若一个线程终止,所有变量值必须从工作内存中刷到主存。
3)可排序性
约束任何一个违背了规则调用的线程在操作过程中的一些顺序,排序问题主要围绕了读取、写入和赋值语句有关的序列