Programmingバックエンド開発者

Javaにおける 'volatile' 変数とは何ですか?また、'synchronized' との違いは何ですか?volatileを使用する場合とその目的は何ですか?

Hintsage AIアシスタントで面接を突破

答え

volatile は、変数の修飾子であり、すべてのスレッドによってその変数の変更が可視化されることを保証します。変数がvolatileとして宣言されている場合、その読み取りと書き込みはローカルキャッシュをバイパスして主メモリから直接行われます。これにより、スレッド内で値のキャッシュが防止されます。

synchronized は、可視性だけでなく、相互排除(mutual exclusion)も保証するキーワードです:同時に1つのオブジェクトの同期ブロックを実行できるのは、1つのスレッドだけです。

volatile 変数は、次の条件に基づいて単純なフラグやカウンタに使用する必要があります:

  • 変数の値が前の状態に依存しない場合(例えば、カウンタは1回だけ書き込まれ、何度も読み取られる);
  • より複雑な操作のシーケンス(check-then-act)が不要な場合。

volatileの使用例:

class Flag { private volatile boolean running = true; public void stop() { running = false; } public void loop() { while (running) { // ... } } }

トリック質問

volatileを使用して変数のインクリメントの原子性を保証できますか?

答え: いいえ、volatile は操作の原子性を保証しません。例えば、counter++ は原子操作ではありません。たとえ counter がvolatileとして宣言されていても、操作は読み取り、変更、書き込み(複数のアクション)が含まれているため、他のスレッドによって中断される可能性があります。原子性は、synchronizedまたはjava.util.concurrent.atomicパッケージのクラスを使用して保証されます。

例:

class Counter { private volatile int count = 0; public void increment() { count++; // 原子操作ではありません! } }

トピックの詳細な知識不足による実際のエラーの例


物語

オンラインショップのプロジェクトで、注文処理スレッドの終了フラグがvolatileなしで実装されました。その結果、1つのスレッドが無限ループに「ハング」し、他のスレッドからの変数の変更が見えませんでした。診断には数日かかりました。


物語

金融システムで、開発者は操作のカウンタにvolatile intを使用しました。ピーク負荷時に操作の数が「失われ始めました」。理由は、複雑なインクリメント操作の原子性の喪失です。


物語

開発者は、クリティカルセクションへのアクセスを相互排除するためにvolatileを使用しようとして、volatileとsynchronizedを混同しました。これにより、データレースやマルチスレッドアプリケーションでのキャッチしにくいバグが発生しました。