什么是伪共享(false sharing)

CPU缓存架构

伪共享

CPU缓存由缓存行组成,通常是 64 字节(常用处理器的缓存行是 64 字节的,比较旧的处理器缓存行是 32 字节),并且它有效地引用主内存中的一块地址

一个 Java 的 long 类型是 8 字节,因此在一个缓存行中可以存 8 个 long 类型的变量。

在程序运行的过程中,缓存每次更新都从主内存中加载连续的 64 个字节。因此,如果访问一个 long 类型的数组时,当数组中的一个值被加载到缓存中时,另外 7 个元素也会被加载到缓存中。

看起来似乎没有什么毛病,但是如果一个 CPU 核心的线程在对 a 进行修改,会导致在同一缓存行的a和b全部失效,如果这时有另一个线程要读取b,则需要重新从内存加载。

当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能这就是伪共享。

解决方式

1、在两个 long 类型的变量之间再加 7 个 long 类型

class Pointer {
    volatile long x;
    long p1, p2, p3, p4, p5, p6, p7;
    volatile long y;
}

2、使用 @sun.misc.Contended 注解

默认使用这个注解是无效的,需要在JVM启动参数加上 -XX:-RestrictContended才会生效

@sun.misc.Contended
class MyLong {
    volatile long value;
}

hhhhh