CHM での get 操作は、他のスレッドによって put の正しい値を取得することが保証されていますか?
put()
への呼び出しの前に が完了している限り、確実に保証されget()
ます。CHM はvolatile
アクセスやその他のロックを内部的に使用して、必ずしもsynchronized
キーワードではなく、データが確実に同期されるようにします。
null値が表示されない限り、getは同期されないため、これを求めています。同じレコードが他のスレッドによって更新され、get がロックで使用されることを保証する null 値はどのようになっていますか?
このjavadocを参照していると思います:
値フィールドは最終的なものではなく揮発性であるため、Java メモリ モデルに関しては、非同期リーダーがデータ競合を介して読み取るときに初期値ではなく null を表示することは正当です。これにつながる並べ替えが実際に発生する可能性はほとんどありませんが、Segment.readValueUnderLock メソッドは、同期されていないアクセス メソッドで null (事前に初期化された) 値が見られる場合のバックアップとして使用されます。
これは、値が最終的なものではないことを説明しようとしているため、コンストラクターでの初期化の順序が変更され、リーダーに null 値が表示される可能性があります。これが、CHM が null 値を格納できない理由だと思います。これにより、null をテストしてから、synchronized
ブロック内で別の get を実行できます。
並べ替えられたコンストラクターの詳細については、次を参照してください:インスタンスの初期化と共有変数への代入の並べ替えは可能ですか?
なぜHashEntry
クラスはファイナルなのですか?誰もそれをサブクラス化しないようにするためだけですか?
はい。これにより、クラスをサブクラス化できなくなります。これにより、不変性が保証されます。誰かがそれをサブクラス化すると、フィールドの可視性が変更され、同時実行契約が破られる可能性があります。
次の [[field]] を final にすることは、スレッドセーフを得るのにどのように役立ちますか?
フィールド (およびフィールドとnext
同様) は、フィールドがコンストラクターで完全に初期化されることを保証するためです。これにより、スレッドの安全性が向上します。これは、オプティマイザーがコンストラクターの最後を超えて初期化を並べ替えることができず、すべてのスレッドがデータを参照できることが保証されているためです。key
hash
final
フィールドに関する情報と、フィールドが上書きを許可しないことvalue
を防ぐ方法については、上記を参照してください。final
put(...)
キーも最終的なのはなぜですか?(キーが HashMap で最終的な理由もわかりません)
と同じ答えHashEntry
。