[英]How does ConcurrentHashMap.get() prevent dirty read?
我正在查看ConcurrentHashMap
的源代码,想知道get()
方法如何在没有任何监视器的情况下工作,代码如下:
public V get(Object key) {
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
int h = spread(key.hashCode());
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = tabAt(tab, (n - 1) & h)) != null) {
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || (ek != null && key.equals(ek))) // mark here for possible dirty read
return e.val;
}
else if (eh < 0)
return (p = e.find(h, key)) != null ? p.val : null;
while ((e = e.next) != null) {
if (e.hash == h &&
((ek = e.key) == key || (ek != null && key.equals(ek)))) // mark here for possible dirty read
return e.val;
}
}
return null;
}
这两条线标志着我都在做同样的事情:检查是否key
当前的Node<K, V>
等于的key
需要。 如果为true
,将返回其对应的值。 但是如果另一个线程在return
和remove()
之前从数据结构中切入这个节点呢? 由于局部变量e
仍然持有被移除节点的引用,GC 会保留它,而get()
方法仍然会返回被移除的值,从而导致脏读。
我错过了什么?
它没有:
检索操作(包括
get
)通常不会阻塞,因此可能与更新操作(包括put
和remove
)重叠。 检索反映了最近完成的更新操作的结果。 (更正式地,给定键的更新操作与报告更新值的该键的任何(非空)检索具有先发生关系。)
这通常不是问题,因为如果get
方法获取了锁, get
永远不会返回不可能发生的结果,从而阻塞其他线程中的更新操作。 您只会得到结果,就好像get
调用发生在更新操作开始之前一样。
所以,如果你不介意get
发生在更新之前还是之后,你也不应该介意它发生在更新期间,因为during和before之间没有明显的区别。 如果您确实希望get
在更新后出现,那么您需要从更新线程发出更新完成的信号; 等待获取锁无论如何都不会实现,因为您可能会在更新发生之前获得锁(在这种情况下,您将获得与未获取锁相同的结果)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.