我注意到Java 8中的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)))
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))))
return e.val;
}
}
return null;
}
问题:如何在一个线程中看到其他线程对哈希映射表所做的修改,因为代码不在同步范畴之下(这会强制执行先行发生关系)?
注意:整个ConcurrentHashMap是一个表的包装器:
transient volatile Node<K,V>[] table;
因此,table
是一个对数组的volatile引用,而不是一个对易失元素数组的引用!这意味着如果有人在此数组中更新一个元素,其他线程将无法看到修改。
ConcurrentHashMap
实际上使用Unsafe
从数组元素中执行 volatile 读取。这就是方法tabAt
的作用。 - Radiodef