迭代器如何在并发哈希映射中失效保护

据我所知, CopyOnWriteArrayList中的迭代器是线程安全的,因为在迭代器创建时由于对arrayList副本的快照引用,并且在此所有可变操作(add, set, and so on)都是通过创建一个新鲜底层数组的副本,因此它们不会影响快照引用引用的副本,对CopyOnWriteArraySet

但是在ConcurrentHashMap情况下挣扎,所以请分享您的观点如果ConcurrentHaspMap情况下迭代器是如何失效保护的


你的问题有点含糊不清 - 你在标题中提到failsafe ,但在体内是thread-safe的。 我假设你的意思是线程安全的。

来自GrepCode的示例源

...检索操作(包括get)通常不会阻塞,因此可能与更新操作(包括put和remove)重叠。 检索反映了最近完成的更新操作的结果。 对于putAll和clear等集合操作,并发检索可能反映插入或删除仅某些条目。 类似地,Iterator和Enumerations在迭代器/枚举创建时或之后返回反映哈希表状态的元素。 他们不会抛出java.util.ConcurrentModificationException。

因此迭代是线程安全的,但它们将合约定义为Iterator和Enumerations返回元素,该元素在创建迭代器/枚举时或之后返回反映哈希表状态的元素。


从文档:“类似地,迭代器和枚举返回的元素反映哈希表在创建迭代器/枚举时或之后的某个时刻的状态。”

ConcurrentHashMap生成的迭代器在创建迭代器时指向哈希表数组,因此它们不会计算导致哈希表被调整大小的更新,这是由规范允许的。 迭代通过散列桶是安全的,因为散列桶引用是volatile


那么,所有的哈希映射(至少,在概念上,真正的实现有点复杂)是一个链表。 通过从第一个节点到最后一个遍地遍历链接列表,可以非常简单地实现失败安全( 不是线程安全 )迭代器。 像这样的东西可以工作:

public boolean hasNext() { 
   if(next != null) return true;
   currentNode = currentNode == null ? null : currentNode.next; // volatile
   while(currentNode == null && ++currentIndex < buckets.length) // assume the length is fixed for simplicity
       currentNode = buckets[currentIndex].head; // also volatile
   if(currentNode != null) next = currentNode.data;
   return currentNode != null;
}

public Object next { 
    if(!hasNext()) throw new NoSuchElementException();
    Object result = next;
    next = null;
    return result;
}

这不是ConcurrentHashMap特有的,它们也可以通过这种方式为常规地图实现,但是没有选择。 为什么? 那么,因为一个“常规”的地图不是线程安全的,所以同时修改它并不是一个好主意,所以,如果发生这种情况,那么很可能是一个错误而不是故意的发生,所以最好是“快速失败”一旦发现这种情况而不是忽视这种情况,继续下去,就有可能发生潜在的微妙风险,难以诊断未来的不一致情况。

如果你问我是否同意这最后一个陈述,答案是一个响亮的“否”:)但显然,java设计师中有足够多的人,至少在做出这个决定时,他们至少回来了。

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

上一篇: How the iterator is failsafe in concurrent hash map

下一篇: CopyOnWriteArrayList implementation concern