Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么要在类jsr166e.Striped64.Cell中额外填充值字段?_Java_Concurrency_Jvm - Fatal编程技术网

Java 为什么要在类jsr166e.Striped64.Cell中额外填充值字段?

Java 为什么要在类jsr166e.Striped64.Cell中额外填充值字段?,java,concurrency,jvm,Java,Concurrency,Jvm,在JSR166中引入的一个类中,作者使用所谓的填充来填充Striped64.Cell类的单值字段 以下是该课程的摘录: /** * Padded variant of AtomicLong supporting only raw accesses plus CAS. The value field is placed * between pads, hoping that the JVM doesn't reorder them. * <p/> * JVM intrinsic

在JSR166中引入的一个类中,作者使用所谓的填充来填充Striped64.Cell类的单值字段

以下是该课程的摘录:

/**
 * Padded variant of AtomicLong supporting only raw accesses plus CAS. The value field is placed
 * between pads, hoping that the JVM doesn't reorder them.
 * <p/>
 * JVM intrinsics note: It would be possible to use a release-only form of CAS here, if it were
 * provided.
 */
static final class Cell {
  volatile long p0, p1, p2, p3, p4, p5, p6;
  volatile long value;
  volatile long q0, q1, q2, q3, q4, q5, q6;

  ...
/**
*AtomicLong的填充变体,仅支持原始访问和CA。此时将放置“值”字段
*在pad之间,希望JVM不会对它们重新排序。
*

*JVM内部注意:如果是,这里可以使用CA的一种只发布的形式 *提供。 */ 静态最终类单元{ 挥发性长p0、p1、p2、p3、p4、p5、p6; 波动性长值; 波动性长q0、q1、q2、q3、q4、q5、q6; ...

然后,作者使用CAS以原子方式修改该值

在Striped64类中,作者还使用Unsafe访问其他两个字段,但不应用任何此类填充


我的问题是:为什么要做这样的事情,引入14个冗余字段来填充单个值字段?

填充是为了防止共享
值的缓存线,否则可能需要从内存中重新获取值,因为缓存线上的其他内容需要整个生产线都将失效。因此,目标是提高性能


为了让事情变得更简单,Java8引入了,它在幕后做同样的事情,只是它是由JVM自己处理的。

虽然我同意assylias的回答,但我认为它需要一些解释

为什么缓存未命中很重要?

因为从主存中读取要比从缓存中读取慢得多。如果您有一个需要经常使用的变量,则将其放入缓存非常重要。此外,如果此变量与其他变量共享同一缓存,则整个缓存线可能会失效

考虑variable1与variable2位于同一缓存上的示例。variable1由thread1使用,variable2由thread2使用。由于它们位于同一缓存线上,因此如果有variable2的更新,thread1需要使用variable1,则需要删除缓存线(即使它不使用此变量!)并从主存读取。这称为错误共享

为什么实际上还有7个多头?

如果仅当JVM不决定对内存重新排序时,则从何处开始读取该变量并不重要(可以从8个“缓存行”中的第3行读取)-缓存线中仍会有一个值。因此,无论您从何处开始读取,缓存线中只会有一个对您重要的值,因此不可能出现“错误共享”的“缓存未命中”


另外,这就是为什么Java对象的大小可以被8整除。

谢谢你的回答。我认为这是正确的,但为什么作为p0..p6+值的总大小的额外q0…q6已经是64字节了,据我所知,这将完全适合单个缓存线?是为了适应实现更长缓存线的其他体系结构吗ines?@SilkEntry它将使用2条缓存线。如果您只有p0,p1…,p6,value,那么您很可能会在一条缓存线上有p0-p6,以及其他一些数据,在另一条缓存线上有值,以及其他数据。