この記事では、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 が先導し、銀行業界のデジタル変革とアップグレードを支援します。

推薦する

バイトダンスの成長コード

達人とは、たとえ誰かが知っていることをあなたに伝えたとしても、あなたがそれを学ぶことができない人です...

ライブ放送ベースダブル11:アンカーはトラフィックを競うことを望まない

「私たちにとって、ダブル11は背景を変えるだけの問題です。根本的な変化は特に大きくはありません。」ダ...

中国でブロックチェーン分野で承認された最初の国家標準「情報技術ブロックチェーンと分散型台帳技術リファレンスアーキテクチャ」

小湘晨報によると、9月11日、成都でブロックチェーン分野での国内初承認国家標準「情報技術ブロックチェ...

ブロックされたウェブサイトを復元する方法の例

私は電子商取引の仕事に応募したばかりです。上司からホームページにウェブサイトのキーワードをプッシュす...

新しいウェブサイトを立ち上げ、2日間で30,000の利益を上げました。高コンバージョンのウェブサイト構築について共有

電話 1 本、注文 1 件、Web サイト 1 つ、チーム 1 つ、Web サイト構築に 1 か月と...

検索エンジンスパイダーと検索ユーザー向けのコンテンツベースのウェブサイトの最適化に関する簡単な説明

1. 忘れられた交通ドメイン名の解決失敗やスペルミスによるトラフィック損失を収集する方法を見つけます...

ハイパースケールからハイブリッドクラウドへ: クラウドコンピューティングの可能性を解き放つ

今日のクラウド コンピューティング市場は、幅広いインフラストラクチャおよびプラットフォーム サービス...

クラウド アプリケーションをより効率的に開発するための 5 つのヒント

クラウド テクノロジーが IT 業界を席巻している今日、クラウド コンピューティングの出現後に会社が...

旅行ウェブサイトのコンバージョン率を向上させるためのいくつかの重要なポイント

旅行サイトは、顧客と直接やりとりするため、インターネット企業にとって大きなプレッシャーがかかるタイプ...

検索マーケティングの基礎について

先週の金曜日、リード氏の招待を受けて、検索マーケティングセミナーで講演をしてきました。参加者はウェブ...

Googleが教えてくれる5つのよくあるSEOの間違い

みなさんこんにちは。私はMuzi Chengzhouです。 chinazのホームページで、Googl...

百度とパーフェクトワールドが中国サイト「宗衡」の買収を協議中と報道

信頼できる業界関係者によると、百度はパーフェクトワールドと中衡中国網の買収について協議している。両者...

オラクルと呼ばれているから、何をしてもいいんですか?

注:この記事の原作者である Matt Asay は、Adobe の開発者エコシステムの責任者です。こ...

実用的な情報: Baidu のランキングにはキーワードデータの分析のみが必要です

Baidu ランキングは常に SEOER の焦点です。検索エンジン最適化は以前ほど重要ではなく、人気...

ビッグデータ、クラウドコンピューティング、人工知能に関する知識と理解

1. ビッグデータの概念ビッグデータとは、より強力な意思決定、洞察、プロセス最適化機能を実現するため...