4

Javadocから

Map m = Collections.synchronizedMap(new HashMap());
      ...
  Set s = m.keySet();  // Needn't be in synchronized block
      ...
  synchronized(m) {  // Synchronizing on m, not s!
      Iterator i = s.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

2 つのクエリ:

1) m.keySet() によって返される Set もコレクション ラッパーですか、それとも非同期セットですか?

編集:

2) m で同期する必要がありますか?

 synchronized(m) {  // Synchronizing on m, not s!

m の代わりに s で同期できませんか?

4

4 に答える 4

5

1: はい、マップとミューテックスを共有する同期セットを返します。

2: はい、反復中に手動でロックを保持する必要があります。そうしないと、 next() の呼び出しの間に変更を加えることができ、それでも問題が発生します。HashMap の仕様の一部であることを思い出してください。たとえば、別のスレッドがm.put("foo", "bar"); への 2 つの呼び出しの間に実行するとi.next()next()ConcurrentModificationException がスローされます。これを防ぐには、マップ全体をロックして、イテレータの操作が完了するまで誰もマップを変更できないようにします。セットだけをロックしても、誰もマップに追加するのを止めることはできません。

同時アクセスが発生している間に反復する必要がある場合は、ConcurrentMap の実装を調べて、作業をより簡単にする必要があります。

于 2012-05-19T06:28:37.463 に答える
3

1) 返されるセットは、SynchronizedSetロックするために同じミューテックスを使用する です。

2)マップは個別のミューテックス オブジェクトではなく、それ自体では同期しないため、マップで同期しても、マップにアクセスできる他のスレッドがマップを変更するのを止めることはありません。これは、マップを変更したすべてのコードがマップ上で同期されている場合にのみ機能します。 マップはそれ自体で同期しますが、奇妙なことに、別のmutex変数を使用してそれ自体を参照します。したがって、マップ上で同期すると、同期化されたラッパーを介したマップへの他の変更が防止されます。メソッドによって返される同期セットで同じミューテックスが使用されることに注意してくださいkeySet()

于 2012-05-19T06:27:51.187 に答える
1

EDITED:以前は間違っていました。

  1. これはSynchronizedSet、SynchronizedMap インスタンス自体で同期されています。
  2. ループにいるときにマップがあなたの下から変更されないようにするために、m で同期する必要があります。

覚えておいてください - Set は元のマップに裏打ちされた単なるビューです。そのため、マップが変更されないようにする必要があります。

コードを見ることは有益です。1999 行に SynchronizedMap の宣言があります。

于 2012-05-19T06:31:24.693 に答える