1. CPU缓存模型和MESI协议
每个CPU的缓存行分M、E、S、I状态
1.缓存行一开始是无效状态
2.如果本地写,则变成M状态,表示独享且与主存不一致
3.如果本地读,则变成E状态,表示独享且与主存一致
4.如果多个CPU同时读了一份缓存,则变为S状态,表示共享且都与主存一致
5.如果修改了S状态的缓存行,则该缓存行变为M状态,其他CPU上的该缓存变为I状态
6.如果读之前发现是I状态的缓存行,则会从主存中去读
7.在读和写之前,如果发现其他缓存行存在M,则先将它写回主存变为E
2. 指令重排序
分为:
(1)编译器优化重排序(JVM、JIT),不改变单线程程序语义的前提下重新安排执行顺序
(2)指令并行重排序:指令流水线技术为了一次执行多个指令而改变指令顺序
处理器级别重排序的解决:内存屏障
3. volatile实现原理
volatile本质是解决可见性和有序性,无法保证原子性
volatile的本质:在汇编指令中,操作var之前多出一个lock前缀指令lock addl,该lock前缀指令有三个功能:
1.在具体执行上,先对总线和缓存行加锁,在Lock锁住总线和缓存行的时候,其他CPU的读写请求会被阻塞,直到锁释放以后,会把缓存行的的脏数据写入主存(S变为M)
2.其他缓存行数据设为I
3.加入内存屏障
很容易发现前2条是用来解决可见性的(MESI协议保证的),第3条是用来解决有序性的
下面解释有序性的内存屏障的具体实现:
3.1. 内存屏障
分为四种屏障:
(1)LoadLoad Barrier
(2)LoadStore Barrier
(3)StoreStore Barrier
(4)StoreLoad Barrier
volatile写操作前面加入StoreStore屏障,在后面加入StoreLoad屏障

解释一下上面的图:禁止上面的普通写和下面的volatile写重排序,是因为写是Load Store,读是Load,当有了StoreStore屏障了,两个写之间的Load指令顺序限制导致写的有序性。为了保证volatile写和下面的volatile读写的有序性,使用了StoreLoad屏障,则因为写和读都需要Load,所以都只能排在volatile的Store后面了。
volatile读操作后面加入LoadLoad屏障和LoadStore屏障

解释:加入LoadLoad是为了防止volatile读和下面的普通读发生重排序(很容易理解,两个读就是两个Load),LoadStore指令是防止volatile读和下面的普通写发生重排序(也很好理解,写的store放在后面)
关于为什么要这样的排序,是参考的happens before原则的