Disruptor-缓存行填充
伪共享概念
CPU架构
常见的CPU架构如下图:
在某个CPU核心上运行一个线程时,他获取数据是先从L1缓存上面找,没有命中数据时,再从L2缓存上面找、还是没有命中时再从L3缓存上找,如果还没有的话就再从主内存里面找。找到后再一层一层的传递数据。
所以查找数据的顺序为:
L1 》L2 》 L3 》主内存
刷新缓存的顺序为:
主内存 》L3 》L2 》L1
缓存存储结构
在计算机缓存中,存储数据是以缓存行为单位的,不同的系统缓存行的大小也不一样,现在常见的64位操作系统,他每行可以存储64字节数据。比如Java中Long
类型的数据占8个字节,所以一行可以存8个Long数据类型的数据。
所以当加载缓存行中任意一个数据时,其他在当前缓存行里的数据也会一起加载
线程数据共享
当线程共享一个变量时,每个线程的更改都会把最新数据刷新回主内存,如果处理器发现自己缓存行对应的内存地址呗修改,就会将当前处理器的缓存行设置无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据库读到处理器缓存中(嗅探机制)。
伪共享
上面说的是共享一个缓存行的一个数据,这样是完全没问题的。可是当不同线程要使用一个缓存行里的不同数据时,这样就会出现一种伪共享的情况:
尽管变量a
没有被其他线程更改,可以由于他和变量d
在同一缓存行里,所以每次都会受变量d的影响,缓存都会被设置为无效状态,所以每次使用时都会从主内存里重新拉取。这样速度就会大大的打折扣。
RingBuffer的解决方法
在RingBuffer
解决伪共享的方法就是缓存行填充
abstract class RingBufferPad
{
protected long p1, p2, p3, p4, p5, p6, p7;
}