首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在jsr166e.Striped64.Cell类中额外填充了这个值字段?

为什么在jsr166e.Striped64.Cell类中额外填充了这个值字段?
EN

Stack Overflow用户
提问于 2014-02-27 13:05:54
回答 2查看 338关注 0票数 5

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

以下是这门课的节选:

代码语言:javascript
复制
/**
 * 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;

  ...

然后,作者使用CAS原子化地修改该值。

在Striped64类中,作者还使用不安全来访问其他两个字段,但没有应用任何这样的填充。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-02-27 13:15:56

填充是为了防止共享value字段所在的高速缓存行,否则该值可能必须从内存中重新获取,因为缓存行上的其他内容要求整个行无效。因此,我们的目标是提高性能。

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

票数 5
EN

Stack Overflow用户

发布于 2014-02-28 11:55:58

虽然我同意亚述人的回答,但我认为这需要一些解释。

为什么缓存丢失很重要?

因为从主内存读取比从缓存读取要慢得多。如果您有一个需要经常使用的变量,那么让它缓存是很重要的。另外,如果该变量与其他变量共享相同的缓存,则可能会出现整个缓存行可能失效的情况。

考虑一下当variable1与variable2驻留在同一个缓存中时的例子。variable1由thread1使用,variable2由thread2使用。因为它们位于相同的缓存行上,所以如果有variable2的更新,而thread1需要使用variable1,则需要删除缓存行(即使它不使用这个变量!)并从主内存中读取。这被称为false共享

为什么实际上还有7个长?

如果只有JVM没有决定重新排序内存,那么从哪里开始读取这个变量并不重要(您可以从第三行读取它,从8个“缓存行”中读取它)--在缓存行中仍然有一个值。所以,不管你是从哪里开始阅读的,只有一个对你很重要的值会出现在缓存线上,因此不可能出现“错误共享”的“缓存丢失”。

这就是为什么Java对象的大小可以除以8的原因。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22069423

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档