【问题标题】:Different `next` entry of ConcurrentHashMap in JDK 1.6 and JDK 1.7JDK 1.6 和 JDK 1.7 中 ConcurrentHashMap 的不同 `next` 条目
【发布时间】:2015-07-15 12:05:08
【问题描述】:

在 JDK 1.6 中,Doug Lea 在 next 字段之前使用 final

static final class HashEntry<K,V> {
    final K key;
    final int hash;
    volatile V value;
    final HashEntry<K,V> next;

而在 JDK 1.7 中,next 字段前面是 volatile。我还注意到,在 JDK 1.7 中,get 方法采用getObjectVolatile 方法来读取value 字段,该字段具有可变负载语义。

我不明白为什么 Doug Lea 以前使用 final。如果正确性有问题,那他怎么能在JDK 1.7(也是JDK 1.8)中用volatile代替呢?

编辑:

具体来说,我的问题是,我们能否在 JDK 1.6 的实现中将 final 替换为 volatile

【问题讨论】:

  • 这个类不在 Java 8 的 CHM 中。
  • 好的,如果这是你的问题,那么不,你不能。修改器改变的原因是实现完全改变了。这不是一个孤立的变化。
  • @RealSkeptic,你能提供一些细节或文章来解释吗?谢谢。
  • @assylias,对不起,整个实现在 Java 8 中发生了变化,它使用 Node&lt;K,V&gt; 表示键值条目。我应该指出来。

标签: java concurrency hashmap java.util.concurrent concurrenthashmap


【解决方案1】:

第一个问题:

我不明白为什么 Doug Lea 以前使用 final。如果有 正确性有问题,那他怎么能用 volatile 代替 在 JDK 1.7(也是 JDK 1.8)中?

这不是正确性的问题。两种实现在线程安全方面都是正确的。试图解决的问题是减少 CHM 的初始占用空间。在 Java 6 中,将 next 字段设为 final 要求创建的对象至少带有一个占位符。这会导致创建过多的空对象,因此已更改为提供按需创建语义。

具体来说,我的问题是我们可以用 volatile 替换 final 在 JDK 1.6 的实现中?

当然,只要操作继续保持顺序一致,它们就是。


Doug Lea 的一位 cmets 谈到了这种设计变化

 /* 
 * ...
 * Historical note: The previous version of this class relied
 * heavily on "final" fields, which avoided some volatile reads at
 * the expense of a large initial footprint.  Some remnants of
 * that design (including forced construction of segment 0) exist
 * to ensure serialization compatibility. 
 */

所以回答你可能有的另一个问题,为什么最初选择final?为了防止以后发生一些易失性读取。

【讨论】:

  • 我也有同样的想法,但无法自己确认。我想知道您是否对 Java API 提出过类似的问题,您是如何处理它们的?谢谢。
【解决方案2】:

这不是用volatile 替换final 的问题。像RealSkeptic 一样,它在许多其他方法中进行了更改。目的可能是优化ConcurrentHashMap.remove()。在 JDK1.6 中,存储桶(按哈希码分组的对象)的列表是 CopyOnWrite,因此在 remove() 中复制了部分列表,在 JDK1.7 中仅更改了 next 指针。

【讨论】:

    猜你喜欢
    • 2013-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    相关资源
    最近更新 更多