3

Java でのアトミック操作に関する記事を読みましたが、明確にする必要がある疑問がいくつかあります。

int volatile num;
public void doSomething() {
  num = 10;  // write operation
  System.out.println(num)   // read
  num = 20;  // write
  System.out.println(num);  // read
}

だから私は wrwr 4 操作を 1 つのメソッドで実行しましたが、それらはアトミック操作ですか? 複数のスレッドが doSomething() メソッドを同時に呼び出すとどうなりますか?

4

5 に答える 5

7

スレッドが中間状態を認識しない場合、操作はアトミックです。つまり、操作が完全に完了したか、まったく完了していないかのいずれかです。

int フィールドの読み取りはアトミック操作です。つまり、32 ビットすべてが一度に読み取られます。int フィールドの書き込みもアトミックです。フィールドは完全に書き込まれるか、まったく書き込まれません。

ただし、メソッド doSomething() はアトミックではありません。メソッドの実行中に、スレッドが別のスレッドに CPU を譲る場合があり、そのスレッドは、すべてではなく一部の操作が実行されたことを確認する場合があります。

つまり、スレッド T1 と T2 の両方が doSomething() を実行すると、次のことが起こる可能性があります。

T1: num = 10;
T2: num = 10;
T1: System.out.println(num); // prints 10
T1: num = 20;
T1: System.out.println(num); // prints 20
T2: System.out.println(num); // prints 20
T2: num = 20;
T2: System.out.println(num); // prints 20

doSomething() が同期された場合、その原子性が保証され、上記のシナリオは不可能になります。

于 2012-08-17T00:20:58.137 に答える
2

volatileスレッド A とスレッド B がある場合、その変数への変更が両方に表示されることを保証します。したがって、ある時点でスレッド A がこの値を変更した場合、スレッド B は将来それを見ることができます。

アトミック操作は、前述の操作の実行が「1 ステップで」確実に行われるようにします。コード 'x = 10;' を見るとやや混乱します。「1 ステップ」のように見えるかもしれませんが、実際には CPU でいくつかのステップが必要です。アトミック操作はさまざまな方法で形成できますが、そのうちの 1 つは を使用してロックすることsynchronizedです。

  • volatile キーワードが約束すること。
  • オブジェクト (静的メソッドの場合はクラス) のロックが取得され、2 つのオブジェクトが同時にアクセスすることはできません。

以前のコメントで質問したように、ある時点でスレッド A が実行していた 3 つの個別のアトミック ステップがあったとしても、スレッド B がそれらの 3 つのステップの途中で実行を開始する可能性があります。オブジェクトのスレッド セーフを確保するには、3 つのステップすべてをグループ化して、1 つのステップのように動作させる必要があります。これは、ロックが使用される理由の一部です。

注意すべき非常に重要なことは、2 つのスレッドが同時にオブジェクトにアクセスできないようにする場合は、すべてのメソッドを同期する必要があるということです。オブジェクトに格納されている値にアクセスする非同期メソッドをオブジェクトに作成できますが、それによってクラスのスレッド セーフが損なわれます。

java.util.concurrent.atomic図書館に興味があるかもしれません。私もこれらの問題の専門家ではないので、推奨された本をお勧めします: Java Concurrency in Practice

于 2012-08-17T00:22:15.423 に答える
1

volatile 変数に対する個々の読み取りと書き込みはそれぞれアトミックです。これは、スレッドが読み取り中に num の値を変更することはありませんが、各ステートメント間で変更される可能性があることを意味します。そのため、他のスレッドが同じことを行っているときに実行doSomething中のスレッドは、10 または 20 を出力し、その後に別の 10 または 20 を出力します。すべてのスレッドが の呼び出しを終了するとdoSomething、num の値は 20 になります。

于 2012-08-16T23:51:17.203 に答える
0

Brian Roach のコメントに従って、私の回答が変更されました。

この場合は整数であるため、アトミックです。

Volatile は、スレッド間の可視性のみを保証できますが、アトミックではありません。volatile を使用すると、整数の変更を確認できますが、変更の統合を保証することはできません。

たとえば、long と double は予期しない中間状態を引き起こす可能性があります。

于 2012-08-16T23:56:24.523 に答える