WeakHashMap.put(..)の二重呼び出しの背後にある理由は何ですか?
-
05-07-2019 - |
質問
このブログ投稿は、文字列IDイディオムごとにミューテックスを実装する方法。使用される文字列IDは、HttpSession IDを表すためのものです。
- Mutexインスタンスの周りにWeakReferenceをラップする必要があるのはなぜですか? StringからMapを作成する方が良いとは思わない->ミューテックス?
-
putを2回呼び出す必要があるのはなぜですか?
public Mutex getMutex( String id ) { Mutex key = new MutexImpl( id ); synchronized( mutexMap ) { WeakReference<Mutex> ref = mutexMap.get( key ); if( ref == null ) { mutexMap.put( key, new WeakReference<Mutex>( key ) ); return key; } Mutex mutex = ref.get(); if( mutex == null ) { mutexMap.put( key, new WeakReference<Mutex>( key ) ); return key; } return mutex; } }
解決
ループおよびブルーノコンデほぼカバーしていますが、そのコードを書いてから...
設計目標は、ユーザーがリリースメカニズムを呼び出さないようにすることでした。ミューテックスは、ユーザーが参照しなくなったときにガベージコレクションの対象となります。
WeakReferenceをラップする必要がある理由 Mutexインスタンスの周辺?
マップは WeakHashMap です。 :
private final Map mutexMap = new WeakHashMap();
このマップは、mutexへの参照を保持するために使用されますが、キーと値に同じオブジェクトを使用する場合、オブジェクトはガベージコレクションの対象になりません。 Javadoc:
実装ノート:値オブジェクト WeakHashMapで普通に保持されています 強い参照。したがって、注意が必要です 値オブジェクトがすることを保証するために取られた 独自のキーを強く参照しない、 直接的または間接的に これにより、キーが 破棄されました。値オブジェクト を介して間接的にキーを参照する場合があります WeakHashMap自体;あれは 値オブジェクトは強く参照する場合があります 関連付けられている他のキーオブジェクト 値オブジェクトは、順番に、強く参照します 最初の値オブジェクトのキーに。 これに対処する1つの方法は、ラップすることです 内の値自体 挿入前のWeakReferences、として in:m.put(key、new WeakReference(value))、次に 各getでアンラップします。
そうではない からマップを作成する方が良い 文字列-&gt;ミューテックス?
その文字列値がガベージコレクションされるのはいつですか?毎回同じ参照が渡されていますか? intern()それに呼ばれた?インターンを呼び出した場合、ストリングはどのくらいの期間存続しますか?文字列がキーである場合、mutexは、参照を保持する必要がなくなった後、ガベージコレクションに適格ではない可能性があります。
putを2回呼び出す必要があるのはなぜですか?
メソッドがマップ内のミューテックスへの強い参照を取得できるようになるまで、2つのケースを処理する必要があります。
- WeakReference にはガベージコレクトされた(またはそもそもそこになかった)
- WeakReferenceのコンテンツは、参照が取得された後にガベージコレクションされます
put は一度だけ呼び出されます。メソッドは直後に戻ります。
(WeakReferenceは2番目のプットで再利用できますが、大幅な改善になるとは思いません。)
もちろん、誰かがコードの誤りを見つけた場合はお知らせください。喜んで修正します。また、単体テストは実装がリークしないことを確認しようとするので、コードを自由に変更して、テストを実行するとどうなるかを確認してください。
他のヒント
WeakHashMapの値オブジェクトは、通常の強い参照によって保持されます。したがって、値オブジェクトが直接または間接的に独自のキーを強く参照しないように注意する必要があります。これにより、キーが破棄されないようになります。値オブジェクトは、WeakHashMap自体を介してそのキーを間接的に参照する場合があることに注意してください。つまり、値オブジェクトは、関連する値オブジェクトが最初の値オブジェクトのキーを順番に参照する他のキーオブジェクトを強く参照する場合があります。これに対処する1つの方法は、m.put(key、new WeakReference(value))のように、挿入する前にWeakReferences内で値自体をラップしてから、各getでアンラップすることです。
1-@Loopには良い答え。
2-エントリがWeakReferencesでラップされていると仮定すると、実行が行に到達する前に WeakReference
が収集される可能性があるため、2番目の put
が必要です。
Mutex mutex = ref.get();
この場合:
- エントリが
map
にまだ存在していない可能性があります
- 存在する場合、
Mutex mutex = ref.get();
の実行前に収集される場合があります
WeakReference
は、httpセッションIDを参照する必要があるためにのみ使用されると言えます。セッションが終了したという通知を常に100%確実に受け取ることができるとは限らないため、マップが成長し続けることになります。
最初にputを呼び出すのは、マップにキーが含まれていないためです。 2回目は、マップにキーが含まれていたが、参照が存在しなくなったためです。