Concurrent collections question 77 of 180 junior
Many threads count words into one map. How do you make the counting correct?
- A
HashMap, withgetand thenput - A
ConcurrentHashMap, withgetand thenput, since each call is thread safe - Correct:
ConcurrentHashMap.merge(word, 1L, Long::sum), which updates one key atomically Collections.synchronizedMap, withgetand thenput
Every call on a ConcurrentHashMap is thread safe, but two calls in a row are not one operation.
With get then put, two threads read the same count, both add one, and one increment is lost. The
map is fine; the read-modify-write around it is the race. A synchronized wrapper has exactly the same
hole, because it locks each call, not the pair.
The fix is to hand the whole update to the map, which runs it atomically for that key:
ConcurrentHashMap<String, Long> counts = new ConcurrentHashMap<>();
counts.merge(word, 1L, Long::sum);
compute and computeIfAbsent give the same per-key guarantee. When one key is very hot, the
threads queue on that key's bin, and the usual next step is a LongAdder per key:
counts.computeIfAbsent(word, k -> new LongAdder()).increment(). The map lookup is then read-only for
existing words, and the increment spreads over cells.
Quiz yourself on Concurrent collections Suggest a correction