I've observed that ConcurrentHashMap has been entirely rewritten in Java 8 to be more "lock-free". I've browsed the code of the get() method and see that there is no explicit lock mechanism:
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; } Question:
How it is possible to see from one thread, modifications done to this hashmap from other threads, since the code isn't under a synchronize umbrella (which would enforce a happens-before relation)?
Note: The entire ConcurrentHashMap is a wrapper of a table: transient volatile Node<K,V>[] table;
So table is a volatile reference to an array, not a reference to an array of volatile elements! Which means that if someone is updating an element inside this array, the modification won't be seen in other threads.
ConcurrentHashMapactually does perform volatile reads from the array elements, usingUnsafe. That's what the methodtabAtdoes.Unsafeis onputs not reads.