文章目录
1:概念
JMM即Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内
存、CPU指令优化等。
2:解决的问题
JMM体现在以下几个方面
- 原子性-保证指令不会受到线程上下文切换的影响(比如说是n++,如果发生线程上下文切换的话,那就破坏了这一条指令的执行)
- 可见性-保证指令不会受cpu缓存的影响
- 有序性-保证指令不会受cpu指令并行优化的影响
3:可见性
(1):问题的引出
可见性是指一个线程对一个变量进行修改,另外一个线程可以看的到
可见性问题是由CPU的缓存导致的,多核CPU均有各自的缓存,这些缓存要与内存进行同步。(其实就是多线程环境下,一个线程对一个变量的改变了,而另一个线程没看到,那么的话还是按照原来的变量的值进行计算的话,那么就会出错)。
(2):如何解决
我们可以对该变量加上 volatile 关键字,这样的话,每次线程都是从主存中去取变量,这样就解决了缓存中数据与主存中数据不一致的问题。我们也可以使用关键字 synChronized 关键字来进行解决可见性问题,只不过synChronized是重量级锁,会影响性能。
(3):拓展
- volatile适合在一个写线程和多个读线程中使用,只能保证变量在内存中的可见性,并不能防止上下文切换带来的原子性问题。
- 但是对变量加上 volatile关键字并不能接解决 原子性问题;但终归还得是靠老大哥synChronized来上锁,既能防止上下文切换解决原子性问题,也可以解决变量可见性问题。
4:有序性
(1):问题的引出—指令重排
为什么会有指令重拍呢,主要是CPU进行优化,提高处理速度造成的。一条指令可以分为 取指令·指令译码·执行指令·内存访问·数据写回 CPU可以在一个时钟周期内,执行不同指令中的不同阶段,也就是同时将5条指令同时进行中,那么其实这样的话,就会出现指令重排问题,因为在一个CPU时钟周期内,我们执行的不是一条完整的指令。
(2):如何解决指令重拍呢
主要也是在相关变量上加上 volatile关键字
5:volatile原理
(1):内存屏障
- volatile的底层实现原理是内存屏障,Memory Barrier(Memory Fence)
- 对volatile变量的写指令后会加入写屏障
- 对volatile变量的读指令前会加入读屏障
(2):如何保证可见性呢
- 写屏障:保证在该屏障之前的,对共享变量的改动都同步到主内存中
- 读屏障:保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据

(3):如何保证有序性呢
- 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
- 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
- 其实也就是有了内存屏障,那么就有了有序性。




337

被折叠的 条评论
为什么被折叠?



