You can see the source code. (I'm looking at JDK 6) HashMap.get () is pretty simple:
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
Where hash () makes some additional changes and XORing to "improve" your hash code.
ConcurrentHashMap.get () is a bit more complicated, but not much
public V get(Object key) { int hash = hash(key.hashCode()); return segmentFor(hash).get(key, hash); }
Again, hash () performs some shifts and XORing. setMentFor (int hash) does a simple array search. The only tricky one in Segment.get (). But even this is not like rocket science:
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); // recheck } e = e.next; } } return null; }
The only place it gets the lock is readValueUnderLock (). The comments say that it is technically legal for the memory model, but was never known.
Overall, the code seems to be very similar to both. Quite a bit better organized in ConcurrentHashMap. Therefore, I would suggest that the performance is pretty similar.
However, if it is really very rare, you might consider using a copy-to-write mechanism.
source share