JMM抽象描述了Java线程和主内存之间的关系。
每个线程都有一个自己的工作内存,共享变量保存在主内存中,每个线程工作内存中都有一份共享变量的副本。
线程间的通信:
(1)首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
(2)然后,线程B到主内存中去读取线程A之前已更新过的共享变量。
JMM中线程的工作内存只是抽象的概念,并不是实际存在,大概相当于L1、L2、L3高速缓存。
一个线程修改了共享变量后,怎么立即被其他线程看到?
volatile,通过内存屏障实现可见性
synchronized,ReentrantLock,通过锁实现可见性
final,限制共享变量不能为修改
上面8种原子操作指令,单独某一个都是原子性的,但合起来就不是原子性的。
例如,i++操作就不是原子性的。
volatile,不能保证原子性
synchronized,ReentrantLock,可以保证原子性
CPU在执行程序时,为了提高性能,会对指令进行重排序,主要分为三种:
(1)编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
(2)指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
(3)内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
是一种JMM层面抽象出来的概念,描述的是一种屏障的功能
在CPU层面上来说,就是一些特殊的指令
(1)一类是强制读取主内存,强制刷新主内存的内存屏障,叫做Load屏障和Store屏障
(2)另外一类是禁止指令重排序的内存屏障,有四个分别叫做LoadLoad屏障、StoreStore屏障、LoadStore屏障、StoreLoad屏障
(1)lfence,是一种Load Barrier 读屏障。在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据
(2)sfence, 是一种Store Barrier 写屏障。在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存
(3)mfence, 是一种全能型的屏障,具备ifence和sfence的能力
不是,lock本质上是一种锁。
JMM和JVM是在不同层次上的划分,两者基本没任何关系。
JMM描述的是线程和内存之间的关系。
JVM是运行时的数据区划。