50

Java メモリ モデルでは、a の書き込みintはアトミックであることが義務付けられています。つまり、あるスレッドで値 (4 バイトで構成される) を書き込み、別のスレッドでそれを読み取ると、すべてのバイトを取得するか、まったく取得しませんが、2 つの新しいバイトと2古いバイトなど。

については保証されませんlong0x1122334455667788ここで、前に保持されている変数に書き込むと、0別のスレッドで0x112233440000000orが読み取られる可能性があります0x0000000055667788

現在、仕様では、オブジェクト参照が int または long サイズのいずれかである必要はありません。型の安全性の理由から、アトミックに書き込まれることが保証されていると思いますが、64 ビット VM では、これらの参照は 64 ビット値 (単なるメモリ アドレス) である可能性があります。

ここに私の質問があります:

  • これをカバーするメモリモデルの仕様はありますか (私は見つけていません)?
  • 長時間書き込みは 64 ビット VM でアトミックである疑いがありますか?
  • VM は参照を 32 ビットにマップする必要がありますか?

よろしく、ステフェン

4

1 に答える 1

63

参照の読み取り/書き込みは常にアトミック

JLS セクション 17.7を参照してください: double および long の非アトミック処理

Java プログラミング言語のメモリ モデルの目的上、不揮発性の long または double 値への 1 回の書き込みは、2 つの個別の書き込み (32 ビットの半分ごとに 1 回) として扱われます。これにより、スレッドが 1 つの書き込みから 64 ビット値の最初の 32 ビットを参照し、別の書き込みから 2 番目の 32 ビットを参照する状況が発生する可能性があります。

volatile long 値と double 値の書き込みと読み取りは、常にアトミックです。

リファレンスの書き込みと読み取りは、それらが 32 ビットまたは 64 ビットの値として実装されているかどうかに関係なく、常にアトミックです。

一部の実装では、64 ビットの long または double 値に対する 1 つの書き込みアクションを、隣接する 32 ビット値に対する 2 つの書き込みアクションに分割すると便利な場合があります。効率のために、この動作は実装固有です。Java 仮想マシンの実装では、long 値と double 値への書き込みを原子的に、または 2 つの部分で自由に実行できます。

Java 仮想マシンの実装では、可能な限り 64 ビット値を分割しないようにすることをお勧めします。プログラマーは、共有 64 ビット値を volatile として宣言するか、プログラムを正しく同期して複雑化を回避することをお勧めします。

(強調を追加)

AtomicReference

古い値と新しい値を調整したい場合、または特定のメモリ効果が必要な場合は、クラスを使用しAtomicReferenceます。

たとえばAtomicReference::getAndSet、新しい値を原子的に設定しながら古い値を返し、2 つのステップの間に別のスレッドが介入する可能性を排除します。volatileメモリ セマンティクスを使用します。

于 2010-04-05T01:36:36.157 に答える