计算机运行时,CPU是执行指令的地方,而指令会需要一些数据的读写。程序的运行时数据都是存放在主存的,而主存又特别慢(相对),所以为了解决CPU和主存之间的速度差异,计算机都引入了高速缓存。
CPU和缓存的数据交换过程中,并不是以字节为单位的。而是每次都会以Cache Line为单位来进行存取
Cache Line其实就是一段固定大小的内存空间,一般为64字节
每个cpu核心自己使用,而不同核心又可能涉及共享变量问题,所以各个高速缓存间势必会有一致性的问题,MESI就是解决这些问题的一种方式
在MESI协议中,每个Cache line有4个状态,可用2个bit表示,它们分别是:
M(Modified):这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中;
E(Exclusive):这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中;
S(Shared):这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中;
I(Invalid):这行数据无效。
如果Core0和Core1都在使用一个共享变量变量A,都会在自己的Cache里有一份A的副本,分布在不同的CacheLine
如果大家都没有修改A,则Core0和Core1里变量A所在的Cache Line的状态都是S
如果Core0修改了A的值,则此时Core0的Cache Line变为M,Core1 的Cache Line变为I
这样CPU就可以通过CacheLine的状态,来决定是删除缓存,还是直接读取什么的
CPU从cache中读取数据时候,会比较地址是否相同,如果相同则检查cache line的状态,再决定该数据是否有效 无效则从主存中获取数据 或根据一致性协议发生一次数据推送
所有内存的传输都发生在一条共享的总线上,而所有的处理器都能看到这条总线,CPU缓存不仅仅在做内存传输的时候才与总线打交道,而是不停在嗅探总线上发生的数据交换,跟踪其他缓存在做什么,所以当一个缓存代表它所属的处理器去读写内存时,其它处理器都会得到通知,它们以此来使自己的缓存保持同步,只要某个处理器一写内存,其它处理器马上知道这块内存在它们的缓存段中已失效
写失效
多个cpu从主内存读取同一个数据到各自的高速缓存,档其中某个cpu修改缓存里的数据,该数据会立马同步到主内存,其他cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效
当一个CPU修改了数据,如果其他CPU有该数据,则通知其为无效;
写更新
当一个CPU修改了数据,如果其他CPU有该数据,则通知其更新;
MESI协议可以保证cache的一致性,为什么还需要volatile这个关键词来保证可见性(内存屏障)
MESI协议:把变量从工作内存中同步到主内存中,就需要按顺序地执行store和write操作
Java内存模型只要求8大操作(原子操作)必须按顺序执行,而没有保证必须是连续执行
volatile修饰的变量的read、load、use操作和assign、store、write必须是连续的,即修改后必须立即同步会主内存,当其它线程需要读取该变量时,使用时必须从主内存刷新,由此保证volatile变量的可见性,volatile这个关键词来保证可见性,是因为在一些情况下,CPU的MESI协议会导致程序执行出现错误