JDK8中的ConcurrentHashmap代码说明

我一直在试图理解JDK8中的ConcurrentHashMap函数,与它在JDK7中的情况形成对照(除了源代码之外,还有一些很好的人,比如Richard http:// www .burnison.ca /用品/的-并发的-ConcurrentHashMap的)。 它看起来在JDK8中已经发生了很大的变化 - 例如本身没有更多的“段”,但不知何故,我感觉到这些变化是为了让代码更简单?

  • 我很难理解ConcurrentHashMap.putVal(...)方法,特别是下面的部分 - 是否直接锁定'segment'列表的头部以插入else {}?:

        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else {//...}
    
  • 不太确定ConcurrentHashMap.casTabAt(...)的代码。

  • 另外,关于JDK8中的ConcurrentHashMap.get(Object key)的源代码,它完全没有锁(我没有看到任何,如果是这样,它没有锁就没有工作,因为我没有看到一个循环'再试一次')或者我没有注意到某种乐观的锁定?

  • 欣赏是否有人可以提供一些提示。


    关于putVal(K key, V value, boolean onlyIfAbsent)方法

    每个桶/桶包含一个hash字段,它以一种非常聪明的方式将两个目的结合在一起:

  • 对于常规垃圾箱(大多数垃圾箱只包含单个项目),它存储映射在这里的密钥的哈希码。 顶部位虽然被清除(它总是被设置为0)。
  • 对于特殊的垃圾箱(目前有3种类型),它包含一个特殊的负值。 聪明的部分是,你只需要最高位来区分正面和负面的价值,并从特殊的箱子中定期分类。 区分不同类型的特殊容器可以自由使用剩余的31位。
  • 本节

    else if ((fh = f.hash) == MOVED)
        tab = helpTransfer(tab, f);
    else {//...}
    

    是在发现地图不是空的并且您试图映射的键的bin不是空的情况下的第一个检查。

    如果您发现的垃圾箱是特殊类型的垃圾箱之一 - 转发垃圾箱,它会很满意。 转发箱是必需的,因为调整大小是同时完成的,并且迭代地并且已经转移(到新表)条目仍然需要可访问(通过旧表中的转发箱)。

    关于casTabAt((Node<K,V>[] tab, int i, Node<K,V> c, Node<K,V> v)方法

    casTabAt()方法用于使用比较和交换操作为对象引用自动设置映射条目。 您仍然可以在几乎所有使用casTabAt()地方看到典型的CAS循环 - 您可以构建要放置的对象,然后尝试将CAS放在适当的位置。 如果觉得奇怪的是一个复杂的构造可以在CAS尝试之前进行,那么可以看看Jeff Preshing的你可以做任何一种原子读 - 修改 - 写操作。

    从某种意义上讲, ConcurrentHashMap仍然使用分条锁,但锁粒度更精细(现在区域从多分档到最低分区),并且锁几乎完全被CAS操作取代。

    关于get(Object key)方法

    get()方法在没有任何锁定的情况下可以离开,因为在大多数情况下,使用volatile语义(通过上述casTabAt()方法和相关的tabAt()方法)设置和检索bin内容。 如果bin包含映射到同一个bin的红黑树条目,并且您可以看到在访问的TreeBin中遍历始终在synchronized块中完成,情况会更复杂。

    链接地址: http://www.djcxy.com/p/16343.html

    上一篇: ConcurrentHashmap in JDK8 code explanation

    下一篇: Java JDK 8 IndexedPropertyDescriptor has changed since JDK 7 with List object