Javaの揮発性キーワードのガイド
1. 概要
この簡単な記事では、Java言語の基本的な、しかし誤解されがちな概念であるvolatileキーワードに焦点を当てます。
Javaでは、各スレッドに作業メモリと呼ばれる個別のメモリ空間があります。これは、操作の実行に使用されるさまざまな変数の値を保持します。 操作を実行した後、スレッドは変数の更新された値をメインメモリにコピーし、そこから他のスレッドが最新の値を読み取ることができます。
簡単に言うと、volatileキーワードは、複数のスレッドがアクセスする場合に、読み取りと書き込みの両方で常にメインメモリに移動する変数をマークします。
2. volatileを使用する場合
変数の次の値が前の値に依存する状況では、メインメモリへの読み取りと書き込みの時間差により、変数の読み取りと書き込みの複数のスレッドが同期しなくなる可能性があります。 。
これは簡単な例で説明できます。
public class SharedObject {
private volatile int count = 0;
public void increamentCount() {
count++;
}
public int getCount() {
return count;
}
}
With no synchronization here, a typical race condition can occur.基本的に、インクリメントとメインメモリへの書き込みの間に実行ギャップがあるため、他のスレッドは値0を認識し、メインメモリに書き込もうとする場合があります。
もちろん、AtomicIntやAtomicLongなどのJava提供のアトミックデータ型を使用することで、競合状態を回避することもできます。
3. 揮発性とスレッドの同期
すべてのマルチスレッドアプリケーションについて、一貫した動作を実現するためにいくつかのルールを確保する必要があります。
-
相互排除-一度に1つのスレッドのみがクリティカルセクションを実行します
-
可視性-共有データに対して1つのスレッドによって行われた変更は、データの一貫性を維持するために他のスレッドから見える
Synchronizedメソッドとブロックは、アプリケーションのパフォーマンスを犠牲にして、上記の両方のプロパティを提供します。
Volatileは、can help ensure the visibility aspect of the data change, without, of course, providing the mutual exclusionであるため、非常に便利なプリミティブです。 したがって、複数のスレッドがコードのブロックを並行して実行していても問題がない場合に役立ちますが、可視性プロパティを確保する必要があります。
4. 発生-保証前
Java 5以降、volatileキーワードは、不揮発性変数を含むすべての変数の値がVolatile書き込み操作とともにメインメモリに書き込まれることを保証する追加機能も提供します。
これは、すべての変数の可視性を別の読み取りスレッドに提供するため、Happens-Beforeと呼ばれます。 また、JVMはvolatile変数の読み取りおよび書き込み命令を並べ替えません。
例を見てみましょう:
Thread 1
object.aNonValitileVariable = 1;
object.aVolatileVariable = 100; // volatile write
Thread 2:
int aNonValitileVariable = object.aNonValitileVariable;
int aVolatileVariable = object.aVolatileVariable;
この場合、Thread 1がaVolatileVariableの値を書き込んだときに、aNonValitileVariableの値もメインメモリに書き込まれます。 And even though it’s not a volatile variable, it is exhibiting a volatile behavior.
これらのセマンティクスを利用することで、クラス内のいくつかの変数のみをvolatileとして定義し、可視性の保証を最適化できます。
5. 結論
このチュートリアルでは、volatileキーワードとその機能、およびJava5以降に加えられた改善点について詳しく説明しました。
いつものように、コード例はover on GitHubにあります。