この記事では、JVMメモリモデルについて詳しく説明します。

この記事では、JVMメモリモデルについて詳しく説明します。

[[422709]]

1. JAVA並行性モデル

共有メモリモデル

共有メモリ同時実行モデルでは、スレッドはプログラムの共通状態を共有し、スレッドはメモリ内の共通状態を読み書きすることで暗黙的に通信します。

このメモリはメインメモリを指しますが、実際には物理メモリの小さな部分です。

2. JAVAメモリモデルの抽象化

1. Javaメモリ内のどのデータがスレッドセーフで、どのデータが安全でないのか

スレッドセーフではありません:

Java では、すべてのインスタンス フィールド、静的フィールド、配列要素がヒープ メモリに格納され、これらのデータはスレッドによって共有されるため、メモリの可視性の問題が発生します。

スレッドセーフティ

ローカル変数、メソッド定義パラメーター、および例外ハンドラー パラメーターは、現在のスレッドの仮想マシン スタック内のデータであり、スレッド間で共有されないため、メモリの可視性の問題は発生しません。

2. スレッド間通信の性質

スレッド間通信の本質は

JMM (JAVA メモリ モデル) がこのプロセスを制御します。 JMM は、スレッドの共有変数への書き込みが他のスレッドに表示されるタイミングを決定します。

上の図から、スレッド間の通信はメインメモリを介して行われ、メッセージが送信されることがわかります。各スレッドが共有データを処理する場合、共有データを現在のスレッドのローカル メモリ (各スレッドには独自のメモリがあります) にコピーして操作します。

メッセージ通信プロセス(データセキュリティの問題を考慮せずに)

スレッド 1 は、共有変数 A をメイン メモリから自身のローカル メモリにロードして処理します。たとえば、A = 1;このとき、変更された共有変数 A はメインメモリにフラッシュされ、スレッド 2 はメインメモリ内の共有変数 A をローカルメモリに読み込んで操作します。データ相互作用プロセス全体はJMMによって制御され、主にメインメモリが各スレッドのローカルメモリとどのように相互作用するかを制御して共有データの可視性を提供します。

3. 並べ替え

プログラムが実行されると、効率を向上させるためにプログラム命令が並べ替えられます。

1. カテゴリの再並べ替え

コンパイラ最適化の並べ替え

コンパイラは、シングルスレッド プログラムのセマンティクスを変更せずに、ステートメントの実行順序を最適化します。

命令セットの並列並べ替え

データ依存関係がない場合、プロセッサはステートメントの実行順序を変更できます。

メモリシステムの並べ替え

プロセッサはキャッシュと読み取り/書き込みバッファを使用するため、ロード操作とストア操作が順序どおりに実行されないように見える場合があります。

2. 再注文プロセス

上記の 3 つの並べ替えにより、並行プログラムを作成するときにメモリの可視性の問題が発生します。

JMM のコンパイラ並べ替えルールでは、特定の種類のコンパイラ並べ替えが禁止されています。

JMM のプロセッサ並べ替えルールでは、Java コンパイラが命令シーケンスを生成するときに特定のメモリ バリア命令を挿入し、メモリ バリア命令を使用して特定のタイプのプロセッサの並べ替えを禁止する必要があります。

3. プロセッサの並べ替え

プロセッサがメモリにデータを書き込むのを待つ遅延を回避するために、プロセッサとメモリの間にバッファが追加され、プロセッサはバッファにデータを書き込み続け、一定時間後にバッファ内のデータを一度にメモリにフラッシュできるようになります。

アドバンテージ:

1. プロセッサの一時停止方法が変更され、プロセッサの動作効率が向上します。

2. メモリにデータを書き込む際のメモリバス使用量を削減する

欠点:

各プロセッサの書き込みバッファは現在のプロセッサにのみ表示されるため、次のシナリオのように、メモリ操作の実行順序は実際の状況と一致しません。

現在のシナリオでは、プロセッサ A とプロセッサ B がそれぞれの書き込みバッファ内のデータをメモリにフラッシュせず、メモリから読み取った A=0 と B=0 を X と Y に割り当てる可能性があります。この時点で、バッファ内のデータがメモリにフラッシュされ、最終結果が実際の目的の結果と一致しなくなります。バッファ内のデータがメモリにフラッシュされたときにのみ、実際の実行と呼べるからです。

メインメモリとワーキングメモリ間の特定の相互作用プロトコル、つまり変数がメインメモリからワーキングメモリにコピーされる方法と、ワーキングメモリからメインメモリに同期される方法は、JMM によって詳細に実装されており、次の 8 つの操作が定義されています。

メインメモリから作業メモリに変数をコピーする場合は、読み取り操作とロード操作を順番に実行する必要があります。変数を作業メモリからメインメモリに同期する場合は、保存操作と書き込み操作を順番に実行する必要があります。ただし、Java メモリ モデルでは、上記の操作を順番に実行する必要があることのみが要求され、連続して実行する必要があることは保証されません。

操作実行フロー図:

同期ルール分析

  • スレッドが理由なくワーキングメモリからメインメモリにデータを同期することを許可しない(割り当て操作が発生していない)
  • 新しい変数はメインメモリ内にのみ作成できます。作業メモリ内の初期化されていない(ロードまたは割り当て)変数を直接使用することはできません。つまり、変数を使用するか保存する前に、まず変数を割り当てるか読み込む必要があります。
  • 同時に変数をロックできるのは 1 つのスレッドだけですが、ロック操作は同じスレッドで複数回実行できます。複数のロック操作の後、同じ回数のロック解除操作が実行された後にのみ、変数はロック解除されます。 lock と unlock はペアで表示する必要があります。
  • 変数に対してロック操作を実行すると、作業メモリ内のこの変数の値がクリアされます。実行エンジンがこの変数を使用する前に、ロードまたは割り当て操作を再実行して変数値を初期化する必要があります。
  • 変数が事前にロック操作によってロックされていない場合、その変数に対するロック解除操作は許可されません。他のスレッドによってロックされた変数のロックを解除することもできません。
  • 変数のロック解除操作を実行する前に、変数をメインメモリに同期させる必要があります(保存および書き込み操作を実行)。

4. メモリバリア命令

プロセッサの並べ替えによって発生するメモリ エラーを解決するために、Java コンパイラは、生成された命令シーケンス内の適切な場所にメモリ バリア命令を挿入し、特定の種類のプロセッサの並べ替えを禁止します。

メモリバリア命令

5. 事前に起こること

事前発生原則は、プログラム実行の原子性、可視性、および順序を保証するのに役立ちます。これは、データの競合があるかどうか、およびスレッドが安全かどうかを判断するための基礎となります。

JMM では、ある操作の結果を別の操作から参照できるようにする必要がある場合、2 つの操作の間に事前発生関係が存在する必要があります (2 つの操作は同じスレッド内にある場合もそうでない場合もあります)。

ルールの内容:

プログラム順序ルール

分岐、ループなど、スレッド内のコードシーケンスを制御することを指します。つまり、スレッド内では意味的なシリアル性が保証され、コードの順序どおりに実行される必要があります。

ロックルール

ロック操作の前にロック解除操作を実行する必要があります。つまり、ロックがロック解除されてからロックされた場合、ロック解除操作の後にロック操作を実行する必要があります (同じロックに対して)。

揮発性変数のルール

揮発性変数への書き込み操作は、この変数の読み取り操作の前に実行される必要があり、これにより揮発性変数の可視性が保証されます。簡単に言えば、スレッドが揮発性変数にアクセスするたびに、メイン メモリから変数の値が強制的に読み取られ、変数が変更されると、最新の値がメイン メモリに強制的に更新されます。いつでも、異なるスレッドが変数の最新の値を見ることができます。

スレッド開始ルール

スレッド開始メソッドstart()は、現在のスレッドのすべての操作の前に実行する必要があります。

スレッド終了ルール

スレッド内のすべての操作は、スレッドが終了する前に実行する必要があります。 Thread.join() メソッドの機能は、現在実行中のスレッドが終了するまで待機することです。スレッド B が終了する前に共有変数が変更されたと仮定します。スレッド A がスレッド B の join メソッドから正常に戻ると、スレッド B による共有変数の変更がスレッド A に見えるようになります。

スレッド中断ルール

中断されたスレッドのコードが割り込みイベントを検出する前に、スレッドは interrupt() メソッドを呼び出します。

オブジェクトの終了ルール

オブジェクトをリサイクルする前にオブジェクトの初期化を完了する必要があります

推移規則

操作 A が操作 B の前に発生し、操作 B が操作 C の前に発生する場合、操作 A は操作 C の前に発生する必要があります。

注: 2 つの操作の間に事前発生関係が存在するということは、前の操作を次の操作の前に実行する必要があることを意味するものではありません。必要なのは、前の操作の結果が次の操作に表示され、前の操作が次の操作の前に順序付けられていることだけです。

6. データの依存性

前の操作の結果は次の操作の結果に影響します。このとき、コンパイラとプロセッサは、データ依存性のある現在の操作を処理するときに、データ依存性のある 2 つの操作の実行順序を変更しません。

注: ここで説明するデータ依存関係は、単一のプロセッサで実行される命令シーケンスまたは単一のスレッドで実行される操作にのみ適用されます。コンパイラとプロセッサは、異なるプロセッサや異なるスレッドの状況を考慮していません。

7. あたかもシリアルのように

シングルスレッドの場合、どのように順序を変更してもプログラムの実行結果は変わりません。したがって、単一のプロセッサまたは単一のスレッドの場合、コンパイラとプロセッサはデータ依存性のある操作を並べ替えません。逆に、操作にデータ依存性がない場合、命令の並べ替えが発生する可能性があります。

4. データの競合と順序の一貫性

データの競合はマルチスレッドの状況でのみ発生します

1. データ競争

変数は 1 つのスレッドで書き込まれ、別のスレッドで読み取られますが、書き込みと読み取りは同期されていません。

2. 順序一貫性

プログラムがマルチスレッド条件下で同期メカニズムを正しく使用できる場合、プログラムの実行は順次一貫性を保ち (シングルスレッド条件下で実行された場合と同様)、プログラム実行の最終結果は期待どおりのものになります。

3. シーケンシャル一貫性メモリモデル

5.3.1 機能:

スレッド内のすべての操作は、プログラムの順序に従って実行する必要があります。すべての操作はアトミックであり、他のスレッドから見える必要があります。

5.3.2 コンセプト:

概念的には、シーケンシャル一貫性には単一のグローバル メモリがあり、どの時点でも最大 1 つのスレッドがそのメモリに接続できます。マルチスレッド シナリオでは、すべてのメモリ読み取りおよび書き込み操作がシリアル化されます。

5.3.3 例:

たとえば、複数の同時スレッド ABC があり、スレッド A には 2 つの操作 A1 A2 があり、その実行順序は A1->A2 です。スレッド B には 3 つの操作 B1、B2、B3 があり、その実行順序は B1->B2->B3 です。 C スレッドには 2 つの操作 C1 C2 があるため、プログラム内で実行される順序は C1->C2 になります。

シナリオ分析:

シナリオ 1: 同時実行セーフ (同期) 実行順序

A1->A2->B1->B2->B3->C1->C2

シナリオ 2: 同時実行が安全でない (非同期) 実行順序

A1->B1->A2->C1->B2->B3->C2

結論は:

非同期シナリオでは、3 つのスレッドがそれぞれ順序どおりに実行されなくても、各スレッド内のそれぞれの操作は順序どおりに実行されます。また、すべてのスレッドは、一貫した全体的な実行順序のみを参照できます。つまり、3 つのスレッドすべてが次の順序を参照します: A1->B1->A2->C1->B2->B3->C2。これは、シーケンシャル一貫性メモリ モデル内のすべての操作が、どのスレッドにもすぐに表示される必要があるためです。

上記のケースのシナリオは JMM には当てはまりません。 JMM では、非同期プログラムの全体的な実行順序が変わるだけでなく、各スレッドから見た操作実行順序も異なります。

例えば、前述のように、スレッド A が変数 a=2 の値を自身のローカルメモリに書き込み、まだメインメモリにフラッシュしていない場合、スレッド A は値が変更されたことを認識しますが、他のスレッド B と C はまったく変更を認識しないため、スレッド A の操作は発生していないと認識します。スレッド A が作業メモリの値をメインメモリにフラッシュバックした場合にのみ、スレッド B と C はそれを参照できます。ただし、同期の場合、順次一貫性モデルと JMM モデルの実行結果は一致しますが、プログラムの実行順序は必ずしも同じではありません。JMM では命令の並べ替えが発生するため、実行順序が不一致になります。

<<:  JVM の詳細な分析: JVM はリフレクションをどのように実装しますか?

>>:  JD Retail Cloud mPaaS が先導し、銀行業界のデジタル変革とアップグレードを支援します。

推薦する

dedispec-$13/Core2Duo/4g メモリ/250g SSD/100m 無制限

dedispec.comは2009年に設立されました。主に独立サーバーのレンタルとホスティングを行っ...

インターネットビジネスモデルと革新的な方法 - ソーシャルビジネス

インターネットのビジネスモデルには 3 つのレベルがあります。最下層は製品中心、次がプラットフォーム...

中学卒の男性が海賊版の高画質大ヒット映画を販売するウェブサイトを立ち上げ、売り上げは数千万本に達した。

中国江蘇ネットは5月12日、大ヒット作の公開後、映画館で映画を観るのが嫌いなファンにとっては、オンラ...

データベースをAmazon Web Servicesに簡単に移行

今日では、企業はデータベースなしではクラウドに移行できません。ただし、クラウド上にはさまざまな種類の...

4399 曹正: 中国のインターネットを解読する

この記事の著者は曹正(4399 建築家)です。この記事は曹正の百度空間 Caoz の和音ブログから引...

テクニカルSEO起業6年目、この数年間の境界に足を踏み入れた私の経験

まず私の状況についてお話しします。資格は低いが諦めなかった私はさまざまな理由で高校を中退し、その後、...

ウェブスパイダーはどのようにしてウェブサイトを収集し、更新するのでしょうか?

インターネット コンテンツの更新プロセスでは、企業の Web サイトのスナップショットの更新を確実に...

GoogleはPRを通すリンクの売買を促している

百度のGreen Radishアルゴリズムの導入に続いて、Googleは公式ブログで再度警告した。リ...

ワールドカップ・クーカーネットワークの「目を引く」から大型スクリーンマーケティングの4つの利点まで

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています4年に一度...

racknerd: 大容量トラフィックの安価な VPS、最低 $22/年、KVM/2.5G メモリ/2 コア/28g ハードディスク/4T トラフィック、Alipay 対応

Racknerd は 2 月末に、トラフィックの多い 3 つの VPS のプロモーションを開始しまし...

Amazon Web Services: 自社開発チップによる先駆者のイノベーション

[51CTO.com からのオリジナル記事] Infrastructure as a Service...

Silu.comの調査は海賊版サイトの閉鎖の波を引き起こし、多くのサイトが自発的に閉鎖された。

新浪テクノロジー 張南中国最大の高画質海賊版ポータルサイトが警察によって閉鎖され、国内の多数の海賊版...

VULTR: 月額 2.5 ドル、フル補充、KVM、512M メモリ、日本を含む 15 のデータセンター

Vultr は誰もがよく知っています。世界中の 15 のデータセンター (日本 VPS、シンガポール...

草の根ウェブマスターは、検索エンジンアルゴリズムの頻繁な変更にどのように対処できるでしょうか?

インターネットに注目している友人は、最近、Google のランキング アルゴリズムの考え方が変わり、...