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]にあります。