Java - 缓存行伪共享

1. 概述

什么是缓存行伪共享?
这个就需要说下计算机的硬件组成,CPU的高速缓存是由缓存行组成的,通常是64字节,并且它有效地引用主内存中的一块地址。在程序运行过程中,每次更新都从主内存中加载连续的64个字节。

假设a和b两个变量是相邻的,一个CPU核心线程会对a进行修改,另外一个CPU核心线程会读取b的值。当a变量被修改后其他包含a的缓存行都将失效,因为其他缓存行中的a不是最新值了。而后者读取b时,发现缓存行已经失效,需要从主内存中重新加载。

这样就出现了一个问题,b 和 a 完全不相干,每次却要因为 a 的更新需要从主内存重新读取,它被缓存未命中给拖慢了。如图所示


2. 如何避免伪共享

  • 在两个 long 类型的变量之间再加 7 个 long 类型
class Pointer {
    volatile long x;
    long p1, p2, p3, p4, p5, p6, p7;
    volatile long y;
}
  • 重新创建自己的 long 类型,而不是 java 自带的 long
class Pointer {
    MyLong x = new MyLong();
    MyLong y = new MyLong();
}

class MyLong {
    volatile long value;
    long p1, p2, p3, p4, p5, p6, p7;
}
  • 使用 @sun.misc.Contended 注解(java8)
@sun.misc.Contended
class MyLong {
    volatile long value;
}

@sun.misc.Contended的原理是在使用此注解的对象或字段的前后各增加128字节大小的padding,从而让CPU将对象预读至缓存时占用不同的缓存行,这样,就不会造成对方缓存行的失效。
:默认使用这个注解是无效的,需要在JVM启动参数加上 -XX:-RestrictContended才会生效,建议使用第三种方式。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容