java中什么是 伪共享_【JMM】内存模型之伪共享(False Sharing)

在对称多处理器(SMP)系统中,每个处理器均有一个本地高速缓存。内存系统必须保证高速缓存的一致性。

当不同处理器上的线程修改驻留在同一高速缓存行中的变量时就会发生假共享,结果导致高速缓存行无效,并强制执行更新,进而影响系统性能。

如图:

102649793ac9fda949803ea50108dc86.png

false-sharing.gif

线程0和线程1会用到不同变量,它们在内存中彼此相邻,并驻留在同一高速缓存行。高速缓存行被加载到CPU0和CPU1的高速缓存中(灰色箭头)。

尽管这些线程修改的是不同变量(红色和蓝色箭头),高速缓存行仍会无效,并强制内存更新以维持高速缓存的一致性。

缓存系统中是以缓存行(cacheline)为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。最常见的缓存行大小是64个字节。一个Java的long类型是8字节,因此在一个缓存行中可以存8个long类型的变量。所以,如果你访问一个long数组,当数组中的一个值被加载到缓存中,它会额外加载另外7个,这会带来一些优势。但是也有伪共享问题,比如两个线程,修改long数组的第一个与第七个,会频发发生缓存失效,影响性能。解决办法就是填充,在JDK8中提供了@sun.misc.Contended注解来避免伪共享,

如Striped64类中的Cell:

/**

* Padded variant of AtomicLong supporting only raw accesses plus CAS.

*

* JVM intrinsics note: It would be possible to use a release-only

* form of CAS here, if it were provided.

*/

@sun.misc.Contended static final class Cell {

volatile long value;

Cell(long x) { value = x; }

final boolean cas(long cmp, long val) {

return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);

}

// Unsafe mechanics

private static final sun.misc.Unsafe UNSAFE;

private static final long valueOffset;

static {

try {

UNSAFE = sun.misc.Unsafe.getUnsafe();

Class> ak = Cell.class;

valueOffset = UNSAFE.objectFieldOffset

(ak.getDeclaredField("value"));

} catch (Exception e) {

throw new Error(e);

}

}

}

还有ConcurrentHashMap中的CounterCell:

/**

* A padded cell for distributing counts. Adapted from LongAdder

* and Striped64. See their internal docs for explanation.

*/

@sun.misc.Contended static final class CounterCell {

volatile long value;

CounterCell(long x) { value = x; }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值