我发现ConcurrentHashMap已经在Java 8中被完全重写为更"无锁".我浏览了该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;
}
Run Code Online (Sandbox Code Playgroud)
题:
如何从一个线程中看到从其他线程对此hashmap进行的修改,因为代码不在同步伞下(这将强制执行先发生关系)?
注意:整个ConcurrentHashMap是表的包装器:
transient volatile Node<K,V>[] table;
那么table是对数组的易变引用,而不是对volatile元素数组的引用!这意味着如果有人正在更新此数组中的元素,则不会在其他线程中看到修改.
Joh*_*int 13
这Node#val是volatile在订购之前建立你的发生.
synchronized不是线程安全的要求,它是工具箱中的一个工具,可以使系统线程安全.您将不得不考虑一整套操作ConcurrentHashMap来推断线程安全性.
知道原件ConcurrentHashMap也是非阻塞的是有用的.注意Java-CHM之前的版本
V get(Object key, int hash) {
if (count != 0) { // read-volatile
HashEntry<K,V> e = getFirst(hash);
while (e != null) {
if (e.hash == hash && key.equals(e.key)) {
V v = e.value;
if (v != null)
return v;
return readValueUnderLock(e); // ignore this
}
e = e.next;
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,没有阻塞,那么它是如何工作的?该HashEntry#value是volatile.这是线程安全的同步点.
NodeCHM-8 的等级是相同的.
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,非null值应该确保在发生之前发生 - 在关于put之前的操作的关系之前.