Javaのvolatileキーワードの手引き
1概要
この簡単な記事では、Java言語の基本的ではあるが誤解されがちな概念である
volatile
キーワードに焦点を当てます。
Javaでは、各スレッドは作業メモリと呼ばれる別々のメモリ空間を持ちます。これは、操作を実行するために使用されるさまざまな変数の値を保持します。操作の実行後、threadは変数の更新された値をメインメモリにコピーし、そこから他のスレッドは最新の値を読み取ることができます。
簡単に言うと、
volatile
キーワードは、複数のスレッドがアクセスする場合に、読み取りと書き込みの両方で常にメインメモリに移動するように変数にマークを付けます。
2
volatile
を使用する場合
変数の次の値が前の値に依存している状況では、変数を読み書きする複数のスレッドが、読み書きとメインメモリへの書き戻しの間の時間のずれにより、同期がとれなくなる可能性があります。 。
これは簡単な例で説明できます。
public class SharedObject {
private volatile int count = 0;
public void increamentCount() {
count++;
}
public int getCount() {
return count;
}
}
-
基本的に、インクリメントとメインメモリへの書き込みとの間に実行ギャップがあるため、他のスレッドは値0を見てメインメモリに書き込もうとする可能性があります。
競合条件は、
AtomicInt
や
AtomicLong
などのJava提供のアトミックデータ型を使用することでももちろん回避できます。
3揮発性およびスレッド同期
すべてのマルチスレッドアプリケーションでは、一貫した振る舞いのためにいくつかの規則を守る必要があります。
-
相互排除 – 一度に1つのスレッドだけがクリティカルセクションを実行します
時間
** 可視性 – 1つのスレッドによって共有データに加えられた変更は、
データの一貫性を維持するために他のスレッドから見える
アプリケーションのパフォーマンスを犠牲にして、Synchronizedメソッドとブロックは上記の両方のプロパティを提供します。
Volatile
は非常に便利なプリミティブです。それは、もちろん相互排除を提供することなく、データ変更の可視性の側面を確実にするのを助けることができるからです。したがって、複数のスレッドでコードブロックを並列実行しても問題ない場所では便利ですが、visibilityプロパティを確保する必要があります。
4前払い保証
Java 5以降では、
volatile
キーワードには、不揮発性変数を含むすべての変数の値が
Volatile
write操作とともにメインメモリに書き込まれるようにする追加機能もあります。
これは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
の値もメインメモリに書き込まれます。
それは
volatile
変数ではありませんが、
volatile
動作をしています。
これらのセマンティクスを利用することによって、クラス内のいくつかの変数のみを
volatile
として定義し、可視性保証を最適化することができます。
5結論
このチュートリアルでは、
volatile
キーワードとその機能、およびJava 5以降で改善された機能について詳しく説明しました。
いつものように、コード例はhttps://github.com/eugenp/tutorials/tree/master/core-java-concurrency[over on GitHub]にあります。