1

マルチスレッド アプリケーションでのマップの使用について質問があります。次のようなシナリオがあるとします。

  1. List<Map<String, Object>>スレッドは、Jackson Json によって逆シリアル化されたjson データを受け取ります。
  2. このスレッドは、受信したマップを変更します。
  3. 次に、別のスレッドによって消費されるように、リストをブロッキング キューに入れます。

ご覧のとおり、マップは単一のスレッドによってのみ変更されますが、読み取り専用になり (何も変更されず、変更されなくなります)、別のスレッドに渡されます。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 つの子スレッドを生成します。メイン スレッドが完了すると、子スレッドによるすべての更新が正常に表示されます。

4

2 に答える 2