I have a question about using maps in multithreaded application. Suppose we have such scenario:
- Thread receives json data as
List<Map<String, Object>>
which is deserialized by Jackson Json. - This thread modifies received maps.
- And then puts list into blocking queue to be consumed by another thread.
As you can see, map is modified only by single thread, but then it "becomes" read-only (nothing chagnes, just not modified anymore) and passed to another thread. Next, when I looked into implementations of HasMap
(also TreeMap
) and ConcurrentHashMap
, the latter has volatile
fields while first two isn't. So, which implementation of Map
should I use in this case? Does ConcurrentHashMap
is overkill choice or it must be used due to inter-thread transfer?
My simple tests shows that I can use HashMap/TreeMap
when they are modified synchronously and it works, but my conclusion or my test code may be wrong:
def map = new TreeMap() // or HashMap
def start = new CountDownLatch(1)
def threads = (1..5)
println("Threads: " + threads)
def created = new CountDownLatch(threads.size())
def completed = new CountDownLatch(threads.size())
threads.each {i ->
new Thread({
def from = i * 10
def to = from + 10
def local = (from..to)
println(Thread.currentThread().name + " " + local)
created.countDown()
start.await()
println('Mutating by ' + local)
local.each {number ->
synchronized (map) {
map.put(number, ThreadLocalRandom.current().nextInt())
}
println(Thread.currentThread().name + ' added ' + number + ': ' + map.keySet())
}
println 'Done: ' + Thread.currentThread().name
completed.countDown()
}).start()
}
created.await()
start.countDown()
completed.await()
println('Completed:')
map.each { e ->
println('' + e.key + ': ' + e.value)
}
Main thread spawns 5 child threads which updates common map synchronously, when they complete main thread successfully sees all updates by child threads.