1、计算机结构
(1)出现
冯诺依曼,提出计算机由五大组成部分,输入设备,输出设备存储器,控制器,运算器
(2)CPU
中央处理器,是计算机的控制和运算的核心,我们的程序最终都会变成指令让CPU去执行,处理程序中的数据。
(3)内存
我们的程序都是在内存中运行的,内存会保存程序运行时的数据,供CPU处理。
(4)缓存
CPU的运算速度和内存的访问速度相差比较大。这就导致CPU每次操作内存都要耗费很多等待时间。内存的读写速度成为了计算机运行的瓶颈。于是就有了在CPU和主内存之间增加缓存的设计。
2、Java的内存模型(Java Memory Model)
(1)Java的内存模型
Java内存模型不是Java内存结构。Java内存模型,是Java虚拟机规范中所定义的一种内存模型,Java内存结构是标准化的,屏蔽掉了底层不同计算机的区别。
Java内存模型是一套规范,描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节
Java内存模型是一套在多线程读写共享数据时,对共享数据的可见性、有序性、和原子性的规则和保障。
(2)主内存与工作内存之间的交互
3、JMM内存模型的理解
(1)概念
JMM模型是抽象的概念,描述的是多线程与内存间的通信,java线程内存模型与CPU缓存模型类似,是标准化的用于屏蔽掉各种硬件和操作系统的内存访问差异
jvm适用于管理内存的,JMM是管理线程的,是不同的概念
JMM定义的是工作内存与主内存数据交互的一个标准
(2)JMM的八大原子操作
- lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
- unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
- read(读取):把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
- load(载入):它把read操作从主内存中得到的变量值放入工作内存的变量副本中
- use(使用): 把工作内存中的一个变量值传递给执行引擎
- assign(赋值):它把个从执行引擎接收到的值赋给工作内存的变量
- store(存储):把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作
- write(写入):把store操作从工作内存中的个变量的值传送到主内存的变量中
volatile能够保证右边的线程修改initFlag后左边的线程能够感知到(变量的可见性问题)
(3)JMM缓存不一致问题底层机制
总线加锁(性能很低)
CPU从主存读取数据到缓存区当中,总线会加锁锁定该缓存对应的主存区域,来自其他CPU或者总线代理的控制请求将被阻塞,无法读写该数据直到锁定被释放。
M(修改)E(独占)S(共享)I(无效)缓存一致性协议
多CPU从主存读取同一数据到各自缓存区中,该数据在lock前缀指令执行期间已经在处理器内部的缓存中被锁定,缓存被锁定期间其他CPU无法读写该数据,直到该缓存数据被修改同步回主存 后,其它CPU通过总线嗅探机制感知数据变化及时失效自己缓存中的数据,在下一轮指令周期从主存重新load数据
读取数据的时候向总线发送读消息(假如此时左边的线程已经存在initFlag),将此消息发送到右边的CPU,该CPU通过总线嗅探机制发现有线程正在读取initFlag,右边的线程读取完之后,会对读取到的变量进行lock,修改变量后再进行unlock,再向总线发送写的消息,,左边的线程捕捉到消息后将读取到的initFlag变量置位无效(因为该线程读取到的变量已经被其他的线程修改了)并丢弃
此时,左边的线程需要重新读取数据的话,会想总线发送读消息,右边的线程检测到该消息后会将修改后的变量同步到主存,然后左边的线程就可以读取更新后的数据了
(4)Volatile可见性实现原理
JMM内存交互层面: volatile修饰的变量的read、load、 use操作和assign、store、write必须是连续的,即修改后必须立即同步回主内存,使用时必须从主内存刷新,由此保证volatile变量的可见性。
底层实现:通过汇编lock前缀指令,它会锁定变量缓存行区域并写回主内存,这个操作称为缓存锁定
- 缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据(MESI协议)(存在这种情况的话,会进行总线裁决)
- 一个处理器的缓存回写到内存内存会导致其他处理器的缓存无效(MESI协议)IA32架构