JDK7中ConcurrentHashMap中的scanAndLockForPut方法的source codes表示:
private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
HashEntry<K,V> first = entryForHash(this, hash);
HashEntry<K,V> e = first;
HashEntry<K,V> node = null;
int retries = -1; // negative while locating node
while (!tryLock()) {
HashEntry<K,V> f; // to recheck first below
if (retries < 0) {
if (e == null) {
if (node == null) // speculatively create node
node = new HashEntry<K,V>(hash, key, value, null);
retries = 0;
}
else if (key.equals(e.key))
retries = 0;
else
e = e.next;
}
else if (++retries > MAX_SCAN_RETRIES) {
lock();
break;
}
else if ((retries & 1) == 0 &&
(f = entryForHash(this, hash)) != first) {
e = first = f; // re-traverse if entry changed
retries = -1;
}
}
return node;
}
我了解代码的含义,但是如果输入,我不知道这是什么意思:
else if ((retries & 1) == 0 && (f = entryForHash(this, hash)) != first)
我的问题是:
为什么我们必须做“((重试和1)== 0”)?
编辑:
我有点想通了。这是因为常量MAX_SCAN_RETRIES:
static final int MAX_SCAN_RETRIES = Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
在单核处理器中,MAX_SCAN_RETRIES =1。因此,线程第二次进入循环“while(tryLock)”时,不必检查第一个节点是否已更改。
但是,在多核处理器中,这将类似于检查while循环中是否每2次更改第一个节点。
以上解释正确吗?
最佳答案
让我们分解一下:
1:
(retries & 1) == 0
对于奇数返回1,对于偶数返回0。基本上,要想过去,即使这个数字是偶数,也有二分之一的机会。
2:
f = entryForHash(this, hash)
f是一个临时变量,用于存储段中最新条目的值。
3:
(/* ... */) != first
检查值是否更改。如果确实如此,它将把当前条目移到开始处,并再次重新链接链接的节点以尝试获取锁。