7

final Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer, Map<String,Integer>>();
Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);

と同じ

volatile Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer,   Map<String,Integer>>();
Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);

内部マップが異なるスレッドによってアクセスされる場合は?

または、このようなものが必要です:

volatile Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer, Map<String,Integer>>();
volatile Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);

それが「カスケードされた」マップではない場合、final と volatile は最終的に、すべてのスレッドが常に Map の正しい内容を確認できるようにするという同じ効果があります...しかし、Map 自体にマップが含まれている場合はどうなりますか?例のように...内部マップが正しく「メモリバリア」であることを確認するにはどうすればよいですか?

タンク!トム

4

3 に答える 3

10

volatileアタッチされている変数の値を読み取る他のスレッドの機能にのみ影響します。別のスレッドがマップのキーと値を参照する機能にはまったく影響しません。たとえば、volatile int[]. 参照を変更した場合、つまり参照が指す実際の配列を変更した場合、配列を読み取る他のスレッドはその変更を確認することが保証されます。ただし、配列の 3 番目の要素を変更すると、そのような保証はありません。

statusisの場合final、包含クラスの構築によりhappens-before後続の読み取りとの関係が作成されるため、ステータスの値を確認できます。同様に、変数への読み取りは、volatile変数への最新の参照割り当てを確認することが保証されています。実際のマップを頻繁に交換するのとは異なり、キーを変更するだけで全体的なマップ オブジェクトはそのままです。

この質問については、次のドキュメントを参照する必要がありますConcurrentHashMap

通常、取得操作 (get を含む) はブロックされないため、更新操作 (put および remove を含む) と重複する場合があります。検索は、開始時に保持されている最新の更新操作の結果を反映します。

これは奇妙な言い回しですが、要点は、何らかの操作が返された後にget開始される操作は、そのプットの結果を見ることが保証されているということです。したがって、外側のマップにa さえ必要ありません。JLS を引用します。putvolatile

オブジェクトが完全に初期化された後にのみオブジェクトへの参照を確認できるスレッドは、そのオブジェクトの final フィールドの正しく初期化された値を確認できることが保証されます。

概要

final外側の地図の Aで十分です。

于 2010-06-03T08:19:30.160 に答える
4

Google コレクション、特に、マップをインテリジェントにセットアップおよび作成できるMapMakerに注目する価値があります。より良いガベージ コレクションと有効期限を有効にするために弱い値を設定できるため、マップを使用して効果的なキャッシングを行うことができるのは素晴らしいことです。MapMaker が作成するマップ (:p) は ConcurrentHashMap と同じプロパティを持っているため、そのスレッド セーフに満足できます。

final mapMaker = new MapMaker().weakValues(); //for convenience, assign
final Map<Integer,Map<String,Integer>> status = mapMaker.makeMap();
status.put(key, mapMaker.<String, Integer>makeMap());

statusInner の定義が正しくないように見えるので、確認することをお勧めします。

于 2010-06-03T08:23:54.630 に答える
1

ここでの最良の答えは、volatileスレッドセーフを保証する方法ではないということだと思います。

使用ConcurrentHashMapするだけで十分です。Map finalはい、可能であればトップレベルへの参照を作成しますが、volatileいずれにしても必要ではありません。Map内部の第 2 レベルの参照は、ConcurrentHashMap正しく理解するためのビジネスであり、そうであると想定されています。

于 2010-06-03T08:10:37.377 に答える