## 基本概念
1. JMM本身是一种抽象的概率并不是真是存在,它描述的是一组规定或者规范,通过这组规范定义了程序中访问的方式
2. JMM同步规则
1. **线程解锁前,必须把共享变量的值刷新回主内存**
2. **线程加锁前,必须读取主内存的最新值到自己的工作内存**
3. **加锁解锁必须是同一把锁**
3. 由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存,工作内存是每个线程的私有数据区域,而Java内存模型中规定所有变量的存储在主内存,主内存是共享内存区域,所以的线程都可以访问,单线程对变量的操作(读取赋值等)必须在工作内存进行处理。
4. 首先要将变量从主内存拷贝的自己的工作空间,然后对变量进行操作,操作完成后再讲变量写回主内存,不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝,工作内存是每个线程的私有数据区域,因此不同的线程无法访问对方工作内存,线程间的通信(传值)必须通过主内存来完成。
5. 内存模型图:

## 三大特性:
### 可见性:
代码测试:

如果不加volatile关键字,则主线程会进入死循环,加volatile则主线程能够退出,说明加了volatile关键字变量,当有一个线程修改了值,会马上被另一个线程感知到,当前值作废,重新从主内存中获取值,对其他线程可见,这就是可见性。
### 原子性:
代码测试:

原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败,有着“同生共死”的感觉。代码中通过函数来中断调用,原先修改的值并不会回滚。这就是不符合原子性的规则。
### 有序性(指令重排序):
a. 计算机在执行程序时,为了提高性能,编译器以及处理器常常会对指令重拍,一般分为3种情况:
* 编译器优化的重排
* 指令并行的重排
* 内存系统的重排
b. 单线程环境里面确保程序最终执行的结果 和 代码执行的结果 一致
c. 处理器在进行重排序时必须考虑指令之间的数据依赖性
d. 多线程环境中环境中 **线程交替执行** ,由于编译器优化重排序的存在,两个线程中使用的变量能否保证用的变量是否一致性是无法确定的, **结果是无法预知的** 。
代码测试:

如果两个线程同时执行,method01 和 method02 如果线程 1 执行 method01 重排序了,然后切换的线程 2 执行 method02 就会出现不一样的结果。
## 禁止指令重排序:
volatile实现禁止指令重排序的优化,从而避免了多线程环境下程序出现乱序的现象。需要知道一个概念,内存屏障(memory Barrier)又称为内存栅栏,是一个CPU指令,他的作用有两个:
1. **保证特定操作的执行顺序**
2. **保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)**
由于编译器个处理器都能执行指令重排序优化,如果在指令间插入一条Memory Barrier 则会告诉编译器和CPU,不管什么指令都不能对这条Memory Barrier指令重排序,也就是说通过插入内存屏障禁止在内存屏障前后执行重排优化。内存屏障另一个作用就是强制刷出各种CPU缓存数据,因此任何CPU的线程都能读取到这些数据的最新版本。
* 保守策略下,volatile写插入内存屏障后生成的指令序列:

* 保守策略下,volatile读插入内存屏障后生成的指令序列图:

1. 线程安全性保证,工作内存与主内存同步延迟现象,导致可见性问题:
a. 可以使用synchronzied或volatile关键字解决,它们可以使用一个线程修改后的变量对其他线程可见。
2. 对于指令重排导致可见性问题和有序性问题:
a. 可以利用volatiel关键字解决,因为volatile的另一个作用就是禁止指令重排序优化
JVM之并发编程核心原理JMM(内存模型)