Javaにおける揮発性変数の動作原理と応用

揮発性修飾子の基本特性

volatile修飾子が適用された共有変数(クラスメンバ変数、静的メンバ変数)は次の特性を獲得します:

  1. 異なるスレッド間での可視性の保証(変数変更が即時に他スレッドに反映)
  2. 命令の再順序付けの禁止
  3. 原子性(atomicity)は保証しない

※ synchronizedとLockは可視性・順序性・原子性の全てを保証

メモリ可視性のメカニズム

Javaメモリモデルにおける動作原理:

// スレッド1
int temp = sharedValue;  // 主記憶から読み取り
temp = temp + 10;        // 作業メモリで変更
sharedValue = temp;      // 主記憶へ書き戻し

// スレッド2
int localCopy = sharedValue; // 変更前の古い値を取得

volatile変数は:

  • 書き込み時に直ちに主記憶を更新
  • 他スレッドのキャッシュを無効化

命令再順序付けの制御

典型的なダブルチェックロッキングパターン:

private volatile static Singleton uniqueInstance;

public static Singleton getInstance() {
    if (uniqueInstance == null) {
        synchronized (Singleton.class) {
            if (uniqueInstance == null) {
                uniqueInstance = new Singleton();
            }
        }
    }
    return uniqueInstance;
}

volatileなしの場合:

  1. メモリ割当
  2. 参照代入(未初期化状態)
  3. コンストラクタ実行

volatileによりコンストラクタ完了まで参照代入をブロック

有効な適用ケース

状態フラグ管理

volatile boolean isReady = false;

// 初期化スレッド
configuration = loadSettings();
isReady = true;

// 処理スレッド
while (!isReady) {
    Thread.yield();
}
processConfiguration(configuration);

原子性操作の限界

volatileが保証しない操作例:

volatile int counter = 0;

// スレッド安全ではない
public void increment() {
    counter++;  // 読み取り→変更→書き込みの非原子操作
}

基本型の直接代入のみ原子性を保証:

volatile int flag = 1;  // 安全
volatile DataPacket packet = new DataPacket(); // 参照代入は原子操作

同期メカニズムの比較

特性volatilesynchronized
可視性
順序性
原子性×
競合防止×

タグ: Java マルチスレッド volatile メモリモデル 並行処理

5月16日 18:30 投稿