5
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 of 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
It is clearly possible to synchronize operations manually as well as use constructions 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, it is possible to use ConcurrentHashMap
from 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 to ensure updates atomics in a concurrent.Map
?