152

行の下のどこかを読みました。

Java volatile キーワードはアトミックを意味しません。揮発性を宣言した後、++操作はアトミックになるというよくある誤解です。操作をアトミックにするには synchronized、Java でメソッドまたはブロックを使用して排他的アクセスを確保する必要があります。

volatileでは、2 つのスレッドがプリミティブ変数を同時に攻撃するとどうなるでしょうか?

これは、それをロックする人は誰でも、最初にその値を設定することを意味しますか? その間に、最初のスレッドが値を変更している間に他のスレッドが起動して古い値を読み取った場合、新しいスレッドは古い値を読み取りませんか?

Atomic キーワードと volatile キーワードの違いは何ですか?

4

6 に答える 6

106

Volatile と Atomic は 2 つの異なる概念です。Volatile は、特定の予期される (メモリ) 状態が異なるスレッド間で真であることを保証しますが、Atomics は、変数に対する操作がアトミックに実行されることを保証します。

Java の 2 つのスレッドの次の例を見てください。

スレッド A:

value = 1;
done = true;

スレッド B:

if (done)
  System.out.println(value);

スレッド化のルールから始めてvalue = 0done = falseスレッド B が値を出力するかどうかは未定義であることがわかります。さらに、はその時点でも未定義です! これを説明するには、Java メモリ管理 (複雑になる可能性があります) について少し知っておく必要があります。つまり、スレッドは変数のローカル コピーを作成する場合があり、JVM はコードを並べ替えて最適化することができます。したがって、上記のコードが正確にその順序で実行されます。done を true に設定してからvalueを 1 に設定すると、JIT 最適化の結果が生じる可能性があります。

volatileそのような変数へのアクセスの瞬間に、新しい値が他のすべてのスレッドにすぐに表示され、実行の順序によって、コードが期待どおりの状態になることが保証されるだけです。したがって、上記のコードの場合、volatiledoneとして定義すると、スレッド B が変数をチェックするたびに、変数が false または true のいずれかになり、true の場合は1 にも設定されます。value

volatileの副作用として、このような変数の値はスレッド全体でアトミックに設定されます (実行速度はわずかに低下します)。ただし、これは、長い (64 ビット) 変数 (または同様のもの) を使用する 32 ビット システムでのみ重要です。他のほとんどの場合、変数の設定/読み取りはとにかくアトミックです。しかし、アトミック アクセスとアトミック操作の間には重要な違いがあります。Volatile はアクセスがアトミックであることのみを保証しますが、Atomics は操作がアトミックであることを保証します。

次の例を見てください。

i = i + 1;

i をどのように定義しても、上記の行が実行されたときに値を読み取る別のスレッドが i または i + 1 を取得する可能性があります。これは、操作がアトミックではないためです。他のスレッドが i を別の値に設定した場合、最悪の場合、スレッド A によって以前の値に戻される可能性があります。これは、スレッド A が古い値に基づいて i + 1 を計算している最中だったため、i を設定してから、再びその古い値 + 1 にします。

Assume i = 0
Thread A reads i, calculates i+1, which is 1
Thread B sets i to 1000 and returns
Thread A now sets i to the result of the operation, which is i = 1

AtomicInteger のようなアトミックは、そのような操作がアトミックに行われることを保証します。したがって、上記の問題は発生しません。両方のスレッドが終了すると、i は 1000 または 1001 になります。

于 2013-11-02T18:20:11.133 に答える
16

では、2 つのスレッドが volatile プリミティブ変数を同時に攻撃するとどうなるでしょうか?

通常、それぞれが値を増やすことができます。ただし、場合によっては、両方が同時に値を更新し、合計で 2 増加する代わりに、両方のスレッドが 1 ずつ増加し、1 だけが追加されます。

これは、それをロックする人は誰でも、最初にその値を設定することを意味しますか?

ロックはありません。それがsynchronized目的です。

その間に、最初のスレッドが値を変更している間に他のスレッドが起動して古い値を読み取った場合、新しいスレッドは古い値を読み取りませんか?

はい、

Atomic キーワードと volatile キーワードの違いは何ですか?

AtomicXxxx は volatile をラップするため、基本的に同じです。違いは、インクリメントの実装に使用される CompareAndSwap などの高レベルの操作を提供することです。

AtomicXxxx は lazySet もサポートしています。これは揮発性セットのようなものですが、書き込みが完了するのを待ってパイプラインを停止させることはありません。値を読み取ると、古い値が表示される可能性がありますが、とにかくそれを行うべきではありません。違いは、volatile の設定には約 5 ns かかり、ビット lazySet には約 0.5 ns かかることです。

于 2013-11-02T18:17:04.017 に答える