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
字段,它以一种非常聪明的方式将两个目的结合在一起:
本节
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
块中完成,情况会更复杂。
上一篇: ConcurrentHashmap in JDK8 code explanation
下一篇: Java JDK 8 IndexedPropertyDescriptor has changed since JDK 7 with List object