マルチスレッド アプリケーションでのマップの使用について質問があります。次のようなシナリオがあるとします。
List<Map<String, Object>>
スレッドは、Jackson Json によって逆シリアル化されたjson データを受け取ります。- このスレッドは、受信したマップを変更します。
- 次に、別のスレッドによって消費されるように、リストをブロッキング キューに入れます。
ご覧のとおり、マップは単一のスレッドによってのみ変更されますが、読み取り専用になり (何も変更されず、変更されなくなります)、別のスレッドに渡されます。HasMap
次に、 (もTreeMap
) との実装を調べたところConcurrentHashMap
、後者にはvolatile
フィールドがありますが、最初の 2 つにはありません。では、この場合、どの実装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 つの子スレッドを生成します。メイン スレッドが完了すると、子スレッドによるすべての更新が正常に表示されます。