Java8的@sun.misc.Contended注解

一曲冷凌霜 提交于 2019-11-29 17:43:51

@sun.misc.Contended 介绍

@sun.misc.Contended 是 Java 8 新增的一个注解,对某字段加上该注解则表示该字段会单独占用一个缓存行(Cache Line)。

这里的缓存行是指 CPU 缓存(L1、L2、L3)的存储单元,常见的缓存行大小为 64 字节。

(注:JVM 添加 -XX:-RestrictContended 参数后 @sun.misc.Contended 注解才有效)

@sun.misc.Contended 的作用——避免伪共享

那么单独使用一个缓存行有什么作用?

为了性能和节省空间,一个缓存行可能不止一个变量,里面还会存储着其他变量,即伪共享。但是这对于共享变量,会造成性能问题:

CPU 修改某共享变量 A 时会先锁定 A 所在的缓存行,并且把其他 CPU 缓存上相关的缓存行设置为无效。如果被锁定或失效的缓存行里,还存储了其他不相干的变量 B,则会造成不必要的开销,因为其他线程此时会访问不了 B,或者由于缓存行失效需要重新从内存中读取加载到缓存。而如果 A 单独使用一个缓存行就可以避免此问题。

Java 8 之前的方案

在 Java 8 之前,是通过代码里手动添加属性的方式解决的,如:

class LongWithPadding {
    long value;
    long p0, p1, p2, p3, p4, p5, p6;
}

一个 long 占 8 个字节,再添加 7 个 long 属性就会变成 64 个字节,刚好是一个缓存行大小。

但是注意,Java 7 开始 JVM 做优化时可能会把不用的变量给去掉,所以这种方法并不推荐使用。

适用场景

主要适用于频繁写共享数据上。如果不是频繁写的数据,那么 CPU 缓存行被锁的几率就不多,所以没必要使用了,否则不仅占空间还会浪费 CPU 访问操作数据的时间。

相关文章

一篇对伪共享、缓存行填充和CPU缓存讲的很透彻的文章

Java8使用@sun.misc.Contended避免伪共享

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!