2011-01-26 8 views
1

私は次のように宣言している場合:私は、そうのような呼び出しをチェーンした場合チェーンされたスレッドセーフなコレクションはスレッドセーフですか?

Map<String, Map<String, Person>> families = 
    Collections.synchronizedMap(new HashMap<String, Map<String, Person>>()); 

を:

families.get(lastName).put(firstName, new Person()); 

このスレッドは安全ですか?私には、2つのマップのうち1つだけが同期されているように見えますが、外側の同期マップを経由せずに内側のマップにアクセスすることはできません。束!しかし、今、私は私がした場合は、この何を考えています:

families.put(lastName, Collections.synchronizedMap(new HashMap<String, Person>()); 

その後、は私の連鎖コールをした、チェーン全体のスレッドセーフということでしょうか? get(lastName)put(firstName, new Person())の間に別のスレッドが内部マップを取得できる可能性はありますか?私はチェーン全体のスレッドを安全にしたい場合、同期されたブロックの中に置く必要があると思っていますが、これがうまくいくかどうかも疑問です。

答えて

1

外部get()と内部put()の呼び出しの間に、他のスレッドが外部get()を呼び出して同じ内部マップを取得することは完全に可能です。しかし、それは同期されているので、とにかく安全でなければなりません。

問題は、外側のマップに何かを配置するときです。スレッドは、新しい内部マップを作成する必要があるかどうかをどのように判断しますか?あなたはこのようなコードがあるとします。

if (!families.containsKey(lastName)) { 
    families.put(lastName, Collections.synchronizedMap(new HashMap<String, Person>()); 
} 

は今、これは間違いなくいくつかの他のスレッドが同時に同じことを行うことなどは危険ですので、あなたがのための候補となるそのうちの一つ内側の2つのマップを作成して終了すぐにガベージコレクション。

構造全体と連携するすべてのメソッドを同期するだけでなく、同期マップを使用しない方がはるかに優れています。1つのレベルの同期だけが必要なので、おそらくより高速になります。

4

同期された外側の地図が、あなたはそれであなたが望むことをすることができます。したがって、ではなく、スレッドセーフです。

このシナリオで実際にスレッドの安全性が必要な場合は、マップのマップを含むオブジェクトを作成し、アクセサーを同期させてアクセスを制御できます。コレクションのコレクションを作成するほとんどのシナリオでは、これは良い方法です。

4

内側のマップはではなく、スレッドセーフです。

いくつかの他のスレッドが同じlastName

families.get(lastName).put(firstName, new Person()); 

をした場合、それは、その後の両方でputを呼び出し、その後、他のスレッドが内部のマップを取得し、内部のマップを取得するために、一つのスレッドのために可能です同じ時間とすべてを壊す。 synchronizedMapを使用して

は、多くの場合、正しい同時実行のためには十分ではない - 通常あなたは明示的ではなく、各メソッド呼び出し周りよりも、各取引の周りにロックします。