lazySet
とset
メソッドの違いは何AtomicInteger
ですか?ドキュメントはについて言うことがたくさん持っていませんlazySet
。
最終的には、指定された値に設定されます。
保存された値がすぐに目的の値に設定されるのではなく、将来のある時点で設定されるようにスケジュールされるようです。しかし、この方法の実際の使用法は何ですか?何か例は?
lazySet
とset
メソッドの違いは何AtomicInteger
ですか?ドキュメントはについて言うことがたくさん持っていませんlazySet
。
最終的には、指定された値に設定されます。
保存された値がすぐに目的の値に設定されるのではなく、将来のある時点で設定されるようにスケジュールされるようです。しかし、この方法の実際の使用法は何ですか?何か例は?
回答:
「JDK-6275329:lazySetメソッドをアトミッククラスに追加する」から直接引用:
Mustangの最後の小さなJSR166フォローアップとして、Atomicクラス(AtomicInteger、AtomicReferenceなど)に「lazySet」メソッドを追加しました。これは、ノンブロッキングデータ構造を使用してコードを微調整するときに役立つニッチな方法です。セマンティクスでは、書き込みは以前の書き込みと並べ替えられないことが保証されていますが、他の揮発性書き込みまたは同期アクションが発生するまで、後続の操作で並べ替えられる可能性があります(または他のスレッドからは見えない可能性があります)。
主な使用例は、長期間のガベージリテンションを回避するためだけに、ノンブロッキングデータ構造のノードのフィールドをnullにすることです。他のスレッドがしばらくの間null以外の値を確認しても問題がない場合に適用されますが、構造体が最終的にGC可能であることを確認したいとします。このような場合、null volatile-writeのコストを回避することにより、パフォーマンスを向上させることができます。非参照ベースのアトミックについても、これらの行に沿って他のいくつかの使用例があるため、このメソッドはすべてのAtomicXクラスにわたってサポートされています。
一般的なマルチプロセッサのマシンレベルのバリアの観点からこれらの操作を考えたい人のために、lazySetは、先行するストアとストアのバリア(現在のプラットフォームでは何もしないか非常に安価)を提供しますが、ストアロードバリアは提供しません(これは通常、揮発性書き込みの高価な部分です)。
Atomic*
スコープ内のすべてのスレッドから見えることは保証されていません)。
可視性に関しては、xchgがアトミックであるため、lazySetはrmwスレッド間通信に使用できます。書き込みスレッドプロセスがキャッシュラインの場所を変更すると、読み取りスレッドのプロセッサは次の読み取り時にそれを認識します。これは、インテルCPUのキャッシュコヒーレンスプロトコルが保証されるためです。 LazySetは機能しますが、キャッシュラインは次の読み取り時に更新されます。ここでも、CPUは十分に新しいものでなければなりません。
http://sc.tamu.edu/systems/eos/nehalem.pdf マルチプロセッサプラットフォームであるNehalemの場合、プロセッサは、他のプロセッサがシステムメモリにアクセスするためにアドレスバスを「スヌープ」(傍受)する機能を備えています。内部キャッシュに。これらのスヌーピング機能を使用して、内部キャッシュをシステムメモリおよび他の相互接続されたプロセッサのキャッシュと整合性を保ちます。スヌーピングを介して、あるプロセッサが別のプロセッサが共有状態で現在キャッシュしているメモリ位置に書き込むつもりであることを検出した場合、スヌーピングプロセッサはそのキャッシュブロックを無効にし、次回同じメモリ位置にアクセスするときにキャッシュラインフィルを実行するように強制します。 。
x86 cpuアーキテクチャ用のOracleホットスポットjdk->
lazySet == unsafe.putOrderedLong == xchg rw(nehelem Intel CPUで20サイクルかかるソフトバリアとして機能するasm命令)
x86(x86_64)では、このようなバリアはvolatileまたはAtomicLong getAndAddよりもパフォーマンス面ではるかに安価です。
1つのプロデューサー、1つのコンシューマーキューシナリオでは、xchgソフトバリアは、プロデューサースレッドのlazySet(sequence + 1)の前のコード行を、新しいデータを消費(処理)するコンシューマースレッドコードの前に強制的に実行できます。コンシューマースレッドは、compareAndSet(シーケンス、シーケンス+ 1)を使用して、プロデューサーシーケンスが1つずつ増分されたことをアトミックにチェックする必要があります。
私はHotspotソースコードをたどって、lazySetからcppコードへの正確なマッピングを見つけました:http ://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe 。 cpp Unsafe_setOrderedLong-> SET_FIELD_VOLATILE定義-> OrderAccess:release_store_fence。x86_64の場合、OrderAccess:release_store_fenceはxchg命令を使用するものとして定義されます。
jdk7でそれがどのように正確に定義されているかを確認できます(doug leaがJDK 8の新しいものに取り組んでいます):http ://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/ linux_x86 / vm / orderAccess_linux_x86.inline.hpp
また、hdisを使用して、実行中のlazySetコードのアセンブリを逆アセンブルすることもできます。
別の関連する質問があります: xchgを使用するときにmfenceが必要ですか?
lazySetとその基になるputOrderedの起源とユーティリティに関する幅広い議論は、こちらで確認できます:http ://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html
要約すると、lazySetは、ストアロードフェンスではなくストアストアとして機能するという意味で、弱揮発性書き込みです。要するに、lazySetがJITコンパイルされて、揮発性セットに使用される非常に高価な命令ではなく、コンパイラーで再順序付けできないMOV命令にコンパイルされるということです。
値を読み取るときは、常に揮発性の読み取りを行います(いずれの場合もAtomic * .get()を使用)。
lazySetは、単一のライターに一貫性のある揮発性書き込みメカニズムを提供します。つまり、単一のライターがlazySetを使用してカウンターをインクリメントすることは完全に正当です。同じカウンターをインクリメントする複数のスレッドは、CASを使用して競合する書き込みを解決する必要があります。 incAndGetのAtomic *のカバー。
StoreStore
障壁であると言えるのではなく、StoreLoad
?
以下からの同時-原子パッケージの概要
lazySetには、揮発性変数の書き込み(割り当て)によるメモリ効果があります。ただし、通常の不揮発性書き込みでは順序変更の制約を課さない後続(ただし前ではない)のメモリアクションによる順序変更が可能です。他の使用コンテキストの中で、ガベージコレクションのために、再びアクセスされることのない参照をnullにするときに、lazySetが適用される場合があります。
lazySetに興味がある場合は、他の説明も必要です
アトミックのアクセスと更新のメモリ効果は、Java™言語仕様のセクション17.4で述べられているように、揮発性の規則に従います。
getには、揮発性変数を読み取るメモリ効果があります。
setには、揮発性変数の書き込み(割り当て)によるメモリー効果があります。
lazySetには、揮発性変数の書き込み(割り当て)によるメモリ効果があります。ただし、通常の不揮発性書き込みでは順序変更の制約を課さない後続(ただし前ではない)のメモリアクションによる順序変更が可能です。他の使用コンテキストの中で、ガベージコレクションのために、再びアクセスされることのない参照をnullにするときに、lazySetが適用される場合があります。
weakCompareAndSetは、アトミックに変数を読み取り、条件付きで書き込みますが、発生前の順序付けは作成しません。そのため、weakCompareAndSetのターゲット以外の変数の前または後の読み取りおよび書き込みに関しては保証されません。
compareAndSetおよびgetAndIncrementなどの他のすべての読み取りおよび更新操作には、揮発性変数の読み取りと書き込みの両方のメモリ効果があります。
これが私の理解です、私が間違っている場合は修正してください:lazySet()
「半」揮発性と考えることができます:これは他のスレッドによる読み取りに関しては基本的に不揮発性の変数です。スレッド。ただし、別の書き込み操作が発生すると(他のスレッドからの可能性があります)、揮発性になります。私が想像できる唯一のlazySetの影響はcompareAndSet
です。したがって、を使用した場合lazySet()
、get()
他のスレッドからは古い値を取得できcompareAndSet()
ますが、書き込み操作であるため、常に新しい値を保持します。
compareAndSet
ですか?
再:それをだましてみてください-
これは、揮発性フィールドを特定のストア(例:ref = null;)操作で揮発性ではなかったかのように扱う方法と考えることができます。
それは完全に正確ではありませんが、「OK、私は本当に気にしない」と「うーん、少し考えさせてください」の間で決定を下すことができれば十分でしょう。