CPU分为三级缓存: 每个CPU都有L1,L2缓存,但是L3缓存是多核公用的。
CPU查找数据的顺序为: CPU -> L1 -> L2 -> L3 -> 内存 -> 硬盘
进一步优化,CPU每次读取一个数据,并不是仅仅读取这个数据本身,而是会读取与它相邻的64个字节
的数据,称之为【缓存行】,因为CPU认为,我使用了这个变量,很快就会使用与它相邻的数据,这是
计算机的局部性原理。这样,就不需要每次都从主存中读取数据了。
这个其实很好理解:
比如说这个代码,CPU读到nums[0]这后大概率就会读nums[1],这就是局部性原理的体现,当然一个缓
存行现在是64个字节,这是很多科学家调优的结果,如果设计的太小则难以命中,如果设计的大了则读
取比较慢,这是目前的最优解。
这种多级缓存的结构下,会有什么问题呢?最经典的就是【可见性的问题】,可以简单的理解为,一个
线程修改的值对其他线程可能不可见。
比如两个CPU读取了一个缓存行,缓存行里有两个变量,一个x一个y。第一颗CPU修改了x的数据,还没
有刷回主存,此时第二颗CPU,从主存中读取了未修改的缓存行,而此时第一颗CPU修改的数据刷回主
存,这时就出现,第二颗CPU读取的数据和主存不一致的情况。
为了解决数据不一致的问题,很多厂商提出了自己的解决方案,比如英特尔的MESI协议。
public static void main(String[] args) {
int nums[] = new int[10];
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
}
1
2
3
4
5
6
MESI协议规定每条缓存都有一个状态位,同时定义了一下四种状态:
修改态 (Modified) 此缓存被修改过,内容与住内存不同,为此缓存专有
专有态 (Exclusive) 此缓存与主内存一致,但是其他CPU中没有
共享态 (Shared) 此缓存与住内存一致,但也出现在其他缓存中。
无效态 (Invalid) 此缓存无效,需要从主内存中重新读取。在可见性的问题,当多个线程同时修改相同资源的
时候,还会存在资源的争夺问题。
1
2
3
4
5
评论0