-2

I was reading the implementation of Java11 Concurrent Hashmap. Below is the snipped of 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;
    }

I also read the remove(key) implementation and noticed that upon removal of a key, the corresponding node of the key is not referenced in the hashtable and removed.

Now what will happen to the concurrent get(key) call?

If remove(k1) is called and completed by another thread just before get(k1) was about to return the e.val, the stale value(non-null value) of key would be returned. Hence ignoring the most recently completed update operation.

Is the above statement correct?

harnoor
  • 57
  • 5
  • "Is this spec line correct?" - the answer is always yes. – rzwitserloot Aug 17 '23 at 16:44
  • You are thinking about it incorrectly. Concurrent means __concurrent__. The javadoc itself doesn't do you any favours - but these things are happening exactly simultaneously. Not 'sort of' and not 'well, technically one would inherently finish before the other, no?' - no, maybe in time and space yes, but CPUs work on cached states, and they're both going off of the same state, so, in that sense, __entirely simultaneously__. Hence, if simultaneously one reads `get(key)` and gets V back and the other deletes `key`.. okay. The other thread still gets V back. – rzwitserloot Aug 17 '23 at 16:46
  • If you want to be able to reason about a hashmap in a serial fashion (all events done to the map anywhere in the entire JVM can be placed in a specific order, and each step makes sense in light of all that came before it), then __do not use `ConcurrentHashMap` at all__ - use a plain jane hashmap and use `synchronized`. – rzwitserloot Aug 17 '23 at 16:47
  • CHM is not 'just like a hashmap where all accesses to it are guarded by a `synchronized` block - but faster!' - if that's how it worked, the JVM is a bad tool that should just apply whatever speed increases are available to the base case instead of forcing jumping through hoops. No- CHM is fundamentally a different thing. It allows one thread to change the map whilst another is _simultaneously_ reading from it / also changing it, and still make certain (not total!) promises about what can happen if you do that. Some guarantees must be sacrificed to do that. Serialized thinking is one of those. – rzwitserloot Aug 17 '23 at 16:49
  • I’m voting to close this question because "there is no actual problem to be solved". – skomisa Aug 17 '23 at 18:36
  • Since the whole point of your question is to challenge the accuracy of a claim that you quote then you need to link to the source of that quote. Regardless, your question is hypothetical, and therefore off topic. Test the claim in that quote, and update your question with evidence if you think it is false. – skomisa Aug 17 '23 at 18:41
  • There is no difference between a removal happening right before the `return e.val;` and a removal happening immediately after returning from the `get(…)` call—there is no way to distinguish the two scenarios at the caller side. So if you’re calling `get` and there are concurrent removals (or updates), you always have to face the fact the the return value of `get(…)` is telling you the past, not the present. – Holger Aug 21 '23 at 08:20

0 Answers0