迭代器如何在并发哈希映射中失效保护
据我所知, 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