In Java ConcurrentHashMap
has an interesting property . Operations such as putIfAbsent
, remove
, replace
, computeIfAbsent
, computeIfPresent
, compute
, and merge
are atomic.
Example:
final Map<String, Integer> map = new ConcurrentHashMap<>();
IntStream.rangeClosed(1, 10000)
.parallel()
.forEach(i -> map.merge("key" + (i % 5 + 1), i, Integer::sum));
final long total = map.values().stream().mapToInt(Integer::intValue).sum(); // 50005000
I did not find any similar operation in the API TrieMap
:
val map = TrieMap[String, Int]().withDefaultValue(0)
(1 to 10000).par.foreach(i => map(s"key${i % 5 + 1}") += i)
val total = map.values.sum // valor aleatório, += não é uma operação atomica
You can clearly synchronize operations manually as well as use constructs such as CAS , STM , etc:
(1 to 10000).par.foreach(i => {
val key = s"key${i % 5 + 1}".intern
key.synchronized {
map(key) += i
}
})
Alternatively, you can use ConcurrentHashMap
of Java directly (without using asScala
):
val map = new java.util.concurrent.ConcurrentHashMap[String, Int]()
(1 to 10000).par.foreach(i => map.merge(s"key${i % 5 + 1}", i, Integer.sum _))
val total = map.values().asScala.sum
Is there any simpler / idiomatic way of securing atomic updates in a concurrent.Map
?