我有一个关于在多线程应用程序中使用地图的问题。假设我们有这样的场景:
- 线程接收
List<Map<String, Object>>
由 Jackson Json 反序列化的 json 数据。 - 该线程修改接收到的地图。
- 然后将列表放入阻塞队列以供另一个线程使用。
如您所见, map 仅由单个线程修改,但随后它“变为”只读(没有变化,只是不再修改)并传递给另一个线程。接下来,当我研究HasMap
(also TreeMap
) 和ConcurrentHashMap
的实现时,后者有volatile
字段,而前两个没有。那么,在这种情况下我应该使用哪个实现Map
?ConcurrentHashMap
是矫枉过正的选择还是由于线程间传输而必须使用?
我的简单测试表明,HashMap/TreeMap
当它们被同步修改并且有效时我可以使用,但是我的结论或我的测试代码可能是错误的:
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)
}
主线程产生 5 个同步更新公共地图的子线程,当它们完成主线程成功看到子线程的所有更新时。