web-dev-qa-db-ja.com

AtomicInteger lazySetとセット

lazySetsetメソッドとAtomicIntegerメソッドの違いは何ですか? documentation には、lazySetについてあまり説明する必要はありません。

最終的に指定された値に設定します。

保存された値はすぐに目的の値に設定されるのではなく、将来のある時点で設定されるようにスケジュールされるようです。しかし、この方法の実際の使用法は何ですか?どんな例ですか?

106
Cheok Yan Cheng

"JDK-6275329:AtomicクラスにlazySetメソッドを追加" :から直接引用

おそらくMustangの最後の小さなJSR166のフォローアップとして、Atomicクラス(AtomicInteger、AtomicReferenceなど)に「lazySet」メソッドを追加しました。これは、非ブロッキングデータ構造を使用してコードを微調整するときに役立つニッチな方法です。セマンティクスは、書き込みが以前の書き込みで並べ替えられないことを保証されますが、他の揮発性の書き込みまたは同期アクションが発生するまで、後続の操作で並べ替えられる可能性があります(または同等に、他のスレッドに表示されない可能性があります)。

主な使用例は、長期的なガベージ保持を回避するためだけに、ノンブロッキングデータ構造内のノードのフィールドをヌルにすることです。他のスレッドがしばらくの間null以外の値を認識しても無害な場合に適用されますが、構造が最終的にGC可能になるようにする必要があります。このような場合、null volatile-writeのコストを回避することにより、パフォーマンスを向上させることができます。これらの行に沿って、非参照ベースのアトミックの使用例もいくつかあります。そのため、このメソッドはAtomicXクラスのすべてでサポートされています。

これらの操作を一般的なマルチプロセッサでのマシンレベルのバリアの観点から考えたい人のために、lazySetは先行するストア間バリア(現在のプラットフォームではノーオペレーションまたは非常に安価な)を提供しますが、ストアロードバリアはありません(通常、volatile-writeの高価な部分です)。

109
yawn

lazySetはrmwスレッド間通信に使用できます。xchgはアトミックであるため、ライタースレッドプロセスがキャッシュラインの場所を変更すると、intel 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(sequence、sequence + 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が必要ですか

14
porkchop

LazySetの起源とユーティリティ、および基礎となるputOrderedのより広範な議論は、ここにあります: http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win -for.html

要約すると、lazySetは、ストアロードフェンスではなくストアストアとして機能するという意味で、弱い揮発性の書き込みです。これは、揮発性セットに使用される非常に高価な命令ではなく、コンパイラーによって再順序付けできないMOV命令にコンパイルされるlazySetに要約されます。

値を読み取るときは、常に揮発性読み取りを実行します(いずれにしてもAtomic * .get()を使用)。

lazySetは単一のライターに一貫した揮発性書き込みメカニズムを提供します。つまり、単一のライターがlazySetを使用してカウンターをインクリメントすることは完全に合法です。同じカウンターをインクリメントする複数のスレッドはCASを使用して競合する書き込みを解決する必要があります。 incAndGetのAtomic *のカバー。

11
Nitsan Wakart

Concurrent-atomic package summary から

lazySetは、揮発性変数の書き込み(割り当て)のメモリ効果があります。通常の不揮発性書き込みによる制約の並べ替え。ガベージコレクションのために、再びアクセスされることのない参照をnullにする場合、他の使用コンテキストの中で、lazySetが適用される場合があります。

LazySetに興味がある場合は、他の説明も必要です。

アトミックのアクセスおよび更新のメモリー効果は、一般に、Java™言語仕様のセクション17.4に記載されている揮発性の規則に従います。

getには、揮発性変数を読み取るメモリ効果があります。

setには、揮発性変数の書き込み(割り当て)のメモリ効果があります。

lazySetは、揮発性変数の書き込み(割り当て)のメモリ効果があります。通常の不揮発性書き込みによる制約の並べ替え。ガベージコレクションのために、再びアクセスされることのない参照をnullにする場合、他の使用コンテキストの中で、lazySetが適用される場合があります。

weakCompareAndSet変数をアトミックに読み取り、条件付きで書き込みますが、発生前の順序付けは作成しません。 weakCompareAndSetのターゲット以外の変数。 compareAndSetおよびgetAndIncrementなどの他のすべての読み取りおよび更新操作には、揮発性変数の読み取りと書き込みの両方のメモリ効果があります。

7
Ajeet Ganga

ここに私の理解があり、間違っている場合は私を修正してください:lazySet()を「半」揮発性と考えることができます:それは基本的に他のスレッドによる読み取りに関してlazySetによって設定された値に関する不揮発性変数です他のスレッドからは見えない場合があります。ただし、別の書き込み操作が発生すると揮発性になります(他のスレッドからの場合があります)。私が想像できるlazySetの唯一の影響はcompareAndSetです。したがって、lazySet()を使用すると、他のスレッドからのget()が古い値を取得する可能性がありますが、compareAndSet()は書き込み操作なので常に新しい値を持ちます。

4
jyluo

再:それを馬鹿にしようとする-

これは、揮発性フィールドを特定のストア(例:ref = null;)操作に対して揮発性ではないかのように扱う方法と考えることができます。

それは完全に正確ではありませんが、「OK、私は本当に気にしない」と「うーん、少し考えてみましょう」との間で決定を下すことができれば十分でしょう。

2
Paul Mclachlan