効果的なJavaの本では、それは述べています:
言語仕様は、変数がタイプ
long
またはdouble
[JLS、17.4.7] でない限り、変数の読み取りまたは書き込みがアトミックであることを保証します。
「アトミック」とは、Javaプログラミングのコンテキスト、またはプログラミング全般の意味を教えてください。
volatile long
かvolatile double
、読み取りをアトミックにして書き込みをアトミックにします。
効果的なJavaの本では、それは述べています:
言語仕様は、変数がタイプ
long
またはdouble
[JLS、17.4.7] でない限り、変数の読み取りまたは書き込みがアトミックであることを保証します。
「アトミック」とは、Javaプログラミングのコンテキスト、またはプログラミング全般の意味を教えてください。
volatile long
かvolatile double
、読み取りをアトミックにして書き込みをアトミックにします。
回答:
例は長い説明よりも明確であることが多いため、ここに例を示します。foo
がタイプの変数であるとしますlong
。次の操作はアトミック操作ではありません:
foo = 65465498L;
実際、変数は2つの別々の操作を使用して書き込まれます。最初の32ビットを書き込む操作と、最後の32ビットを書き込む2番目の操作です。つまり、別のスレッドがの値を読み取りfoo
、中間状態を参照する可能性があります。
操作をアトミックにすることは、同期メカニズムを使用して、他のスレッドから操作が単一のアトミックな(つまり、部分的に分割できない)操作として認識されるようにすることからなります。つまり、他のスレッドは、操作がアトミックになるとfoo
、割り当て前または割り当て後のいずれかの値を参照します。しかし決して中間的な価値はありません。
private volatile long foo;
または、変数へのすべてのアクセスを同期するには:
public synchronized void setFoo(long value) {
this.foo = value;
}
public synchronized long getFoo() {
return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized
または、次のものに置き換えますAtomicLong
:
private AtomicLong foo;
これは、「システムの他の部分から瞬時に発生するように見え」、コンピューティングプロセスの線形化可能性の分類に該当するものです。そのリンクされた記事をさらに引用するには:
原子性は、並行プロセスからの分離を保証します。さらに、アトミック操作には通常、成功または失敗の定義があり、システムの状態を正常に変更するか、明らかな影響を与えません。
したがって、たとえば、データベースシステムのコンテキストでは、「アトミックコミット」を使用できます。つまり、更新の変更セットをリレーショナルデータベースにプッシュすると、それらの変更はすべて送信されるか、まったく送信されません。障害が発生した場合、このようにしてデータは破損せず、ロックやキューの結果として、次の操作は別の書き込みまたは読み取りになりますが、事後のみです。変数とスレッドのコンテキストでは、これはほとんど同じで、メモリに適用されます。
あなたの引用は、これがすべてのインスタンスで予期される動作である必要はないことを強調しています。
Atomic vs. Non-Atomic Operationsの投稿が私にとって非常に役立つことを見つけました。
「共有メモリに作用する操作は、他のスレッドと比較して単一のステップで完了する場合、アトミックです。
アトミックストアが共有メモリで実行されると、他のスレッドは変更が半分完了したことを確認できません。
共有変数でアトミックロードが実行されると、一度に表示された値全体が読み取られます。」
次のコードでメソッドm1およびm2を実行する複数のスレッドがある場合:
class SomeClass {
private int i = 0;
public void m1() { i = 5; }
public int m2() { return i; }
}
スレッド呼び出しm2
が0または5を読み取ることが保証されます。
一方、このコードでi
は(どこが長いのですか):
class SomeClass {
private long i = 0;
public void m1() { i = 1234567890L; }
public long m2() { return i; }
}
スレッド呼び出しm2
は、0、1234567890L、またはその他のランダムな値を読み取る可能性があります。これは、ステートメントi = 1234567890L
がaのアトミックであることが保証されていないためですlong
(JVMは2つの操作で最初の32ビットと最後の32ビットを書き込むことができi
、その間にスレッドが観察する可能性があります)。 。
Javaでは、longとdoubleを除くすべてのタイプのフィールドの読み書きはアトミックに発生し、フィールドがvolatile修飾子で宣言されている場合、longとdoubleでもアトミックに読み書きされます。つまり、そこに何があったか、何が起こったのか、または変数に中間結果があり得ないかのいずれかで100%を取得します。