[英]How does ConcurrentHashMap.get() prevent dirty read?
I am looking at the source code of ConcurrentHashMap
and wondering how the get()
method works without any monitor, here's the code:我正在查看
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;
}
The two lines I marked are doing the same thing: checking if the key
of the current Node<K, V>
equals to the key
needed.这两条线标志着我都在做同样的事情:检查是否
key
当前的Node<K, V>
等于的key
需要。 If true
, will return its corresponding value.如果为
true
,将返回其对应的值。 But what if another thread cuts in before return
and remove()
this node from the data structure.但是如果另一个线程在
return
和remove()
之前从数据结构中切入这个节点呢? Since the local variable e
is still holding the reference of the removed node, GC will leave it be and the get()
method will still return the removed value, thus causing a dirty read.由于局部变量
e
仍然持有被移除节点的引用,GC 会保留它,而get()
方法仍然会返回被移除的值,从而导致脏读。
Did I miss something?我错过了什么?
It doesn't : 它没有:
Retrieval operations (including
get
) generally do not block, so may overlap with update operations (includingput
andremove
).检索操作(包括
get
)通常不会阻塞,因此可能与更新操作(包括put
和remove
)重叠。 Retrievals reflect the results of the most recently completed update operations holding upon their onset.检索反映了最近完成的更新操作的结果。 (More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value.)
(更正式地,给定键的更新操作与报告更新值的该键的任何(非空)检索具有先发生关系。)
This is generally not a problem, since get
will never return a result that couldn't have happened if the get
method acquired a lock, blocking the update operation in the other thread.这通常不是问题,因为如果
get
方法获取了锁, get
永远不会返回不可能发生的结果,从而阻塞其他线程中的更新操作。 You just get the result as if the get
call happened before the update operation began.您只会得到结果,就好像
get
调用发生在更新操作开始之前一样。
So, if you don't mind whether the get
happens before or after the update, you also shouldn't mind it happening during the update, because there is no observable difference between during and before .所以,如果你不介意
get
发生在更新之前还是之后,你也不应该介意它发生在更新期间,因为during和before之间没有明显的区别。 If you do want the get
to appear to happen after the update, then you will need to signal from the updating thread that the update is complete;如果您确实希望
get
在更新后出现,那么您需要从更新线程发出更新完成的信号; waiting to acquire a lock wouldn't achieve that anyway, because you might get the lock before the update happens (in which case you'd get the same result as if you didn't acquire the lock).等待获取锁无论如何都不会实现,因为您可能会在更新发生之前获得锁(在这种情况下,您将获得与未获取锁相同的结果)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.