「こんにちは、アミーゴ!」

「こんにちは、エリー!」

「volatile 修飾子について話したいのですが、それが何であるか知っていますか?」

「糸に関係したことだ。正確には覚えていない。」

「それでは、聞いてください。技術的な詳細をいくつか説明します。」

「コンピュータには、グローバル (通常) メモリとプロセッサに内蔵されたメモリの 2 種類のメモリがあります。プロセッサに内蔵されたメモリは、レジスタ、一次キャッシュ (L1)、二次キャッシュ (L2)、およびレジスタに分かれています。第 3 レベル (L3)。

「これらの種類のメモリには速度が異なります。最も高速で最小のメモリはレジスタで、次にプロセッサ キャッシュ (L1、L2、L3)、最後にグローバル メモリ (最も低速) です。」

「グローバル メモリとプロセッサ キャッシュの動作速度は大きく異なるため、Java マシンでは各スレッドが最も頻繁に使用される変数をローカル スレッド メモリ (プロセッサ キャッシュ内) に保存できます。」

「このプロセスをどうにか制御できないでしょうか?」

「そうではありません。すべての作業は Java マシンによって行われます。パフォーマンスの最適化に関しては、Java マシンは非常にインテリジェントです。」

「しかし、私がこれを言う理由はここにあります。小さな問題が 1 つあります。2 つのスレッドが同じ変数を処理している場合、それぞれのスレッドはコピーを独自のローカル キャッシュに保存できます。そして、1 つのスレッドは変数を変更する可能性がありますが、2 番目のスレッドは変数を変更する可能性があります。変数の独自のコピーをまだ使用しているため、変更が認識されない可能性があります。」

「それでは何ができるでしょうか?」

「Java の作成者は、この状況に備えて、volatile という特別なキーワードを提供しました。変数が別のスレッドからアクセスされる場合、Java マシンがその変数をキャッシュに入れないよう、変数を volatile 修飾子でマークする必要があります。これが通常の方法です」見た目:」

public volatile int count = 0;

「ああ、覚えています。これについてはすでに話しました。私はすでに知っています。」

「確かにそうだね。でも、私が話したときに初めて思い出したんだね。」

「あの、ちょっと忘れてたんですけど」

「繰り返しは学習の母です!」

「ここでは、volatile 修飾子に関する新しい事実をいくつか紹介します。volatile 修飾子は、変数が安全に読み書きされることを保証するだけであり、安全に変更されることを保証するものではありません。」

「違いは何ですか?」

「変数がどのように変更されるかを見てください。」

コード 実際に何が起こるか: 説明
count++
register = count;

register = register+1;

count = register;
ステップ 1.
変数 count の値がグローバル メモリからプロセッサ レジスタにコピーされます。

ステップ 2.
プロセッサ内で、レジスタ変数が 1 ずつインクリメントされます。

ステップ 3.
変数の値がプロセッサからグローバル メモリにコピーされます。

「すごい! では、すべての変数はプロセッサ内でのみ変更されるということですか?」

「はい。」

「そして、値はメモリからプロセッサへ、またその逆にコピーされるのですか?」

「はい。」

「volatile 修飾子は、変数 count がアクセスされるときに、変数がメモリから読み取られることを保証します (ステップ 1)。また、スレッドが新しい値を割り当てたい場合、その値は確実にグローバル メモリ内にあります (ステップ 3)。」

「しかし、Java マシンは、ステップ 1 と 3 の間でスレッドの切り替えが行われないことを保証しません。」

「変数を 1 増やすには、実際には 3 回の操作が必要になるということですか?」

"はい。"

「そして、2 つのスレッドが同時に count++ を実行したい場合、それらは互いに干渉する可能性がありますか?」

「はい、チェックしてください:」

スレッド 1 スレッド 2 結果
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

「つまり、変数にアクセスすることはできますが、変更するのは依然として危険ですか?」

「まあ、変えてもいいから気をつけてね☺」

"どうやって?"

同期は 私たちの親友です。」

"そうか。"