oncurrentHashMap(jdk1.7)put操作确定segment后,加锁失败时,遍历链表的目的

ConcurrentHashMap(jdk1.7)put操作确定segment后,加锁失败时,自旋外还在遍历链表,什么目的,感觉毫无意义啊

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;
   }

改成这样有啥问题呢:

private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
        HashEntry<K,V> node = new HashEntry<K,V>(hash, key, value, null);
        int retries = -1; // negative while locating node
        while (!tryLock()) {
            if (++retries > MAX_SCAN_RETRIES) {
                lock();
                break;
            }
        }
        return node;
       }
阅读 1.8k
2 个回答

在网上找到的答案,感觉有一定合理性:
此处遍历链表的原因:希望遍历的链表被CPU cache所缓存,为后续实际put过程中的链表遍历操作提升性能。怎么理解呢?put还是要再去遍历一次(即使链表在缓存中)?因为此时当前线程没有获取到Segment锁,所以不能进行put操作,但可以为put操作做一些准备工作(有可能加载到缓存,在缓存中执行遍历更快),使put的操作更快,从而减少锁竞争。这种思想在remove()方法中也有体现。

这边有两个出口,一个是获取锁,即tryLock()返回true,另外一个是没获取到锁,重试MAX_SCAN_RETRIES后直接lock()等待获取锁。没获取锁时,重试期间,就创建node节点,这样后面就不用创建了,节省时间

推荐问题