変数の同期コピーとローカルコピー
-
13-09-2019 - |
質問
次のイディオムを含むいくつかのレガシーコードを調べています。
Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (myMap) {
item = myMap.get(myKey);
}
Intelli-J のコード インスペクションから得られる警告は次のとおりです。
Synchronization on local variable 'myMap'
これは適切な同期ですか?またその理由は何ですか?
Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (someGlobalInstance.getMap()) {
item = myMap.get(myKey);
}
解決
これが問題としてフラグ付けされた理由がある。
のsomeGlobalInstance.getMap()
によって返されるオブジェクトは常に同じである場合は、、その後、同期ブロックは準グローバルオブジェクトが監視することを使用して、コードが期待される結果を生成することで行います。
私はまた、あなただけget()
/ put()
の呼び出しを同期する必要があり、任意の大きなsynchronizedブロックを持っていない場合、同期化ラッパーを使用するように提案に同意します。しかし、地図があることを確認してください。ののみのラッパーを介してアクセスしたり、バグのために別のチャンスがあります。
は、またsomeGlobalInstance.getMap()
はのの同じオブジェクトのすべての時間を返し、その後もあなたの2番目のコード例が正しく動作しませんしない場合は、上の同期可能性があるので、それもあなたの元のコードよりも悪いかもしれないことに注意してくださいあなたがget()
を呼ぶものとは異なるオブジェクトます。
他のヒント
私は、コードがGetMapリクエスト()メソッドが何をするかに応じて、音かもしれないと思います。それはスレッド間で共有する必要があるインスタンスへの参照を保持している場合、それは理にかなっています。ローカル変数がローカルに初期化されないので、警告は無関係である。
使った方が良いと思います 同期ラッパー あなたの地図のために
アレックスはCollections.synchronizedMap(Map)
を呼び出すことによって同期ラッパーを追加することで正しいここに典型的なアプローチです。しかし、あなたがこのアプローチを取る場合はまだあなたがMap
のロックに同期する必要のある状況があるかもしれません。例えばマップを反復処理するときます。
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<String, String>());
// Synchronized on map to prevent ConcurrentModificationException whilst iterating.
synchronized (syncMap) {
for (Map.Entry<String, String> entry : syncMap.entrySet()) {
// Do work
}
}
それはあなたのローカル変数ことは明らかだとしてあなたの例では、IDEAからの警告は、無視することができます。map
はどこか別の場所(someGlobalInstance
)ではなくメソッド内で作成されているので、潜在的に他のスレッドからアクセスすることができますよりから取得されます。