6

Collections.synchronizedMap()スレッド A によって読み取られ、更新される同期されたマップ (を介して) があります。スレッド B は、 Map.keySet()(読み取り専用) を介してのみマップにアクセスします。

これを同期するにはどうすればよいですか?ドキュメントによると、keySet() (Collections.synchronizedMap の場合) は「同期ブロックにある必要はありません」。スレッド A の読み取り/書き込みアクセスを同期ブロック内に配置できますが、それは必要ですか?

Map.keySet を同期する必要がない場合 (上記のドキュメント リンクによると)、同期されたマップまたは同期されたブロックを使用することさえ奇妙に思えると思います...

更新: keySet の取得に同期は必要ありませんが、keySet の反復を同期する必要があることを見逃していました。それを調べることができずにkeySetを持っていることは特にエキサイティングではないので、最終結果=同期が必要です。代わりに ConcurrentHashMap を使用します。

4

3 に答える 3

3

真の読み取り/書き込み対読み取り/専用ロック ラッパーを作成するには、使用Mapするラッパーを見て、すべてのステートメントを. これはちょっとした作業です。代わりに、適切なことをすべて行う を使用することに切り替えることを検討する必要があります。CollectionssynchronizedMap()synchronizedReentrantReadWriteLockConcurrentHashMap

に関しては、すでにによってブロックされているためkeySet()、ブロックに含まれる必要はありません。Javadocs は、マップを反復処理している場合、複数の操作を行っているため同期する必要があることを指摘しているだけですが、それを実行するクラスにラップされているものを取得する場合は同期する必要はありません自分の同期。synchronizedsynchronizedCollections.synchronizedMap()keySet()SynchronizedSet

最後に、あなたの質問は、何かを読んでいるだけなら同期する必要がないことを暗示しているようです。同期は、競合状態から保護するだけでなく、データが各プロセッサによって適切に共有されることも保証することを覚えておく必要があります。読み取り専用としてアクセスしMapている場合でも、他のスレッドが更新している場合は同期する必要があります。

于 2012-08-22T19:31:03.230 に答える
2

ドキュメントは正しいです。から返されたマップはCollections.synchronizedMap()、元の に送信されたすべての呼び出しを同期して適切にラップしますMap。ただし、keySet() によって返されるセット impl には同じプロパティがないため、同じロックの下で読み取られるようにする必要があります。

この同期がないと、スレッド B がスレッド A によって行われた更新を確認できるという保証はありません。

調査することをお勧めしConcurrentHashMapます。まさにこのユースケースに役立つセマンティクスを提供します。CHM (のようなkeySet()) でコレクション ビューを反復処理すると、便利な同時動作 ("弱い一貫性のある" イテレータ) が得られます。反復時にコレクションの状態からすべてのキーをトラバースします。反復子が作成された後に変更が表示される場合と表示されない場合があります。

于 2012-08-22T19:37:08.923 に答える
2

ドキュメントは、アトミックである必要がある複数ステップの操作を適切に同期する方法を示しています。この場合、マップを反復処理します。

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());
}

実際の反復が同期ブロック内にある必要があることに注意してください。ドキュメントは、 のライブビューであるため、を取得keySet()ても同期ブロックにあるかどうかは問題ではないと言っているだけです。マップ内のキーが、取得中のキー セットへの参照と同期ブロックの開始の間で変更された場合、キー セットはそれらの変更を反映します。Map

ちなみに、あなたが引用したドキュメントは、Map返されたCollections.synchronizedMap. このステートメントは、必ずしもすべての に適用されるわけではありませんMap

于 2012-08-22T19:31:48.083 に答える