Search code examples
concurrencyjava.util.concurrentconcurrenthashmap

ConcurrentHashMap in JDK7 code explanation (scanAndLockForPut)


The source codes of the method scanAndLockForPut in ConcurrentHashMap in JDK7 says:

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

I understand what the codes mean, but what I don't is this else if entry:

else if ((retries & 1) == 0 && (f = entryForHash(this, hash)) != first)

My question is: Why do we have to do "(retries & 1) == 0"?

EDIT: I kind of figure it out. It's all because the constant MAX_SCAN_RETRIES:

static final int MAX_SCAN_RETRIES = Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;

In single core processor, MAX_SCAN_RETRIES = 1. So the second time the thread steps into the loop "while(tryLock)", it doesn't have to check whether the first node was changed.

However, in multi cores processor, this will behave like checking whether the first node is changed every 2 times in the while loop.

Is the above explanation correct?


Solution

  • I've asked this question on the concurrency-interest mailing list, and the author(Doug Lea) himself replied:

    Yes. We need only ensure that staleness is eventually detected. Alternating the head-checks works fine, and simplifies use of the same code for both uni- and multi- processors.

    link

    So I think this is the end of this question.