ホームページ Java &#&チュートリアル Java メモリ モデルの詳細な分析: 逐次一貫性

Java メモリ モデルの詳細な分析: 逐次一貫性

Dec 29, 2016 am 11:58 AM

データ競合と逐次一貫性保証

データ競合は、プログラムが正しく同期されていない場合に発生します。 Java メモリ モデル仕様では、データ競合を次のように定義しています:
あるスレッドで変数を書き込み、
別のスレッドで同じ変数を読み取り、
書き込みと読み取りは同期によって順序付けされません。

コードにデータ競合が含まれている場合、プログラムの実行により直感に反する結果が生じることがよくあります (前の章の例の場合と同様)。マルチスレッド プログラムが正しく同期されている場合、そのプログラムはデータ競合のないプログラムになります。

JMM は、正しく同期されたマルチスレッド プログラムのメモリの一貫性について次の保証を行います:
プログラムが正しく同期されている場合、プログラムの実行は逐次一貫性を保ちます。つまり、プログラムの実行結果は次のようになります。一貫したメモリ モデルでの実行結果は同じです (後で説明するように、これはプログラマにとって非常に強力な保証です)。ここでの同期とは、一般的な同期プリミティブ (ロック、揮発性、および最終) の正しい使用を含む、広い意味での同期を指します。

Sequential Consistency Memory Model

Sequential Consistency Memory Model は、コンピューター科学者によって理想化された理論的な参照モデルであり、プログラマーに強力なメモリ可視性の保証を提供します。逐次整合性メモリ モデルには 2 つの大きな特徴があります:
スレッド内のすべての操作はプログラムの順序で実行される必要があります。
(プログラムが同期されているかどうかに関係なく) すべてのスレッドは単一の操作実行順序のみを確認できます。逐次一貫性のあるメモリ モデルでは、すべての操作がアトミックに実行され、すべてのスレッドに即座に表示される必要があります。

逐次整合性メモリ モデルは、プログラマに次のビューを提供します:

Java メモリ モデルの詳細な分析: 逐次一貫性

概念的には、逐次整合性モデルには、左右に動くスイッチを介して任意のスレッドに接続できる単一のグローバル メモリがあります。同時に、各スレッドはプログラムの順序でメモリの読み取り/書き込み操作を実行する必要があります。上の図から、どの時点でもメモリに接続できるスレッドは最大 1 つであることがわかります。複数のスレッドが同時に実行される場合、図のスイッチング デバイスは、すべてのスレッドのすべてのメモリ読み取り/書き込み操作をシリアル化できます。

より深く理解するために、2 つの模式図を通して逐次整合性モデルの特徴をさらに説明しましょう。

2 つのスレッド A と B が同時に実行されていると仮定します。スレッド A には 3 つの操作があり、プログラム内での順序は A1 -> A2 -> A3 です。スレッド B にも 3 つの操作があり、プログラム内での順序は B1 -> B2 -> B3 です。

これら 2 つのスレッドが正しく同期するためにモニターを使用しているとします。スレッド A は 3 つの操作が実行された後にモニターを解放し、その後スレッド B が同じモニターを取得します。逐次整合性モデルにおけるプログラムの実行効果は、次の図のようになります。

Java メモリ モデルの詳細な分析: 逐次一貫性

次に、2 つのスレッドが同期していないと仮定します。以下は、この非同期プログラムの実行の概略図です。逐次整合性モデルでは:

Java メモリ モデルの詳細な分析: 逐次一貫性

非同期プログラムの逐次整合性モデルでは、全体的な実行順序は順序付けされていませんが、すべてのスレッドは一貫した全体的な実行順序のみを確認できます。上図を例にとると、スレッド A と B による実行順序は、B1 -> A1 -> A2 -> B2 -> A3 -> B3 となります。この保証は、逐次一貫性のあるメモリ モデル内のすべての操作がどのスレッドからも即座に認識できる必要があるため実現されます。

しかし、JMMにはそのような保証はありません。 JMM 内で非同期プログラムの全体的な実行順序が狂っているだけでなく、すべてのスレッドから見たオペレーションの実行順序も矛盾している可能性があります。たとえば、現在のスレッドが書き込まれたデータをローカル メモリにキャッシュし、それをメイン メモリに更新する前は、書き込み操作は他のスレッドの観点からは現在のスレッドにのみ表示され、書き込み操作は行われたものとみなされます。現在のスレッドによって操作がまったく実行されていません。現在のスレッドがローカル メモリに書き込まれたデータをメイン メモリにフラッシュした後でのみ、この書き込み操作を他のスレッドが認識できるようになります。この場合、操作が実行される順序は、現在のスレッドと他のスレッドの間で矛盾します。

同期されたプログラムの逐次一貫性の効果

次に、モニターを使用して前のサンプル プログラム ReorderExample を同期し、正しく同期されたプログラムがどのように逐次一貫性を持つかを確認します。

以下のサンプルコードをご覧ください:

class SynchronizedExample {
int a = 0;
boolean flag = false;

public synchronized void writer() {
    a = 1;
    flag = true;
}

public synchronized void reader() {
    if (flag) {
        int i = a;
        ……
    }
}
}
ログイン後にコピー

上記のサンプルコードでは、スレッド A が Writer() メソッドを実行した後、スレッド B が Reader() メソッドを実行すると仮定しています。これは適切に同期されたマルチスレッド プログラムです。 JMM 仕様によれば、このプログラムの実行結果は、逐次整合性モデルでのこのプログラムの実行結果と同じになります。以下は、2 つのメモリ モデルでのプログラムの実行タイミングの比較表です。

Java メモリ モデルの詳細な分析: 逐次一貫性

逐次整合性モデルでは、すべての操作がプログラムの順序で逐次実行されます。 JMM では、クリティカル セクションのコードを並べ替えることができます (ただし、JMM では、クリティカル セクションのコードがクリティカル セクションの外に「エスケープ」することは許可されません。これにより、モニターのセマンティクスが破壊されます)。 JMM は、モニターを終了するときとモニターに入るときの 2 つの重要な時点で特別な処理を実行し、スレッドがこれら 2 つの時点で順次整合性モデルと同じメモリ ビューを持つようにします (具体的な詳細は後で説明します)。スレッド A はクリティカル セクションで並べ替えられていますが、モニターの相互排他的な実行特性により、スレッド B はクリティカル セクションでのスレッド A の並べ替えを「観察」できません。この並べ替えにより、プログラムの実行結果を変えることなく、実行効率が向上します。

ここから、特定の実装における JMM の基本ポリシーがわかります。(正しく同期された) プログラムの実行結果を変更せずに、コンパイラーとプロセッサーの最適化の扉を可能な限り開くというものです。

非同期プログラムの実行特性

同期されていない、または正しく同期されていないマルチスレッド プログラムの場合、JMM は最小限のセキュリティのみを提供します。スレッドの実行時に読み取られる値は、前のスレッドによって書き込まれた値であるか、デフォルトです。値 (0、null、false)。JMM は、スレッド読み取り操作によって読み取られた値が突然出現しないことを保証します。最小限の安全性を実現するために、JVM はヒープ上にオブジェクトを割り当てるときに、まずメモリ空間をクリアしてから、その上にオブジェクトを割り当てます (JVM はこれら 2 つの操作を内部で同期します)。したがって、オブジェクトに事前にゼロ設定されたメモリが割り当てられている場合、ドメインのデフォルトの初期化はすでに完了しています。

JMM は、非同期プログラムの実行結果が逐次整合性モデルのプログラムの実行結果と一致することを保証しません。同期されていないプログラムが逐次整合性モデルで実行されると、通常は順序が狂い、その実行結果は予測できないためです。非同期プログラムの実行結果が両方のモデルで一貫していることを保証しても意味がありません。

逐次整合性モデルと同様に、非同期プログラムが JMM で実行されると、通常は順序が狂い、その実行結果は予測できません。同時に、これら 2 つのモデルにおける非同期プログラムの実行特性には次のような違いがあります:
逐次整合性モデルは、単一スレッド内の操作がプログラムの順序で実行されることを保証しますが、JMM は単一スレッド内の操作がプログラムの順序で実行されることを保証しません。単一スレッドはプログラムの順序で実行されます (上記のクリティカル セクションで正しく同期されたマルチスレッド プログラムの順序変更など)。これについては以前にも述べたのでここでは繰り返しません。
逐次整合性モデルは、すべてのスレッドが一貫した操作実行順序のみを確認できることを保証しますが、JMM はすべてのスレッドが一貫した操作実行順序を確認できることを保証しません。これについては以前にも述べたのでここでは繰り返しません。
JMM は、64 ビット長の double 変数に対する読み取り/書き込み操作のアトミック性を保証しませんが、逐次整合性モデルはすべてのメモリ読み取り/書き込み操作のアトミック性を保証します。

3 番目の違いは、プロセッサ バスの動作メカニズムに密接に関係しています。コンピュータでは、データはバスを介してプロセッサとメモリの間で受け渡されます。プロセッサとメモリ間の各データ転送は、バス トランザクションと呼ばれる一連の手順を通じて完了します。バス トランザクションには、読み取りトランザクションと書き込みトランザクションが含まれます。読み取りトランザクションはメモリからプロセッサにデータを転送し、書き込みトランザクションはプロセッサからメモリにデータを転送します。各トランザクションはメモリ内の 1 つ以上の物理的に連続したワードを読み取り/書き込みします。ここで重要なのは、バスを同時に使用しようとするトランザクションをバスが同期するということです。 1 つのプロセッサがバス トランザクションを実行している間、バスは他のすべてのプロセッサおよび I/O デバイスによるメモリの読み取り/書き込みを禁止します。バスの動作メカニズムを模式図で説明してみましょう:

Java メモリ モデルの詳細な分析: 逐次一貫性

上図に示すように、プロセッサ A、B、C が同時にバスへのバス トランザクションを開始すると、バス アービトレーションによりプロセッサ A が決定されるとします。調停後の競争に勝ちます (バス調停により、すべてのプロセッサがメモリに公平にアクセスできるようになります)。この時点で、プロセッサ A はバス トランザクションを継続しますが、他の 2 つのプロセッサはメモリ アクセスを再び開始する前に、プロセッサ A のバス トランザクションが完了するまで待つ必要があります。プロセッサ A がバス トランザクション (バス トランザクションがリード トランザクションであるかライト トランザクションであるかに関係なく) を実行しているときに、プロセッサ D がバスに対してバス トランザクションを開始するとします。このとき、プロセッサ D のリクエストはバスによって禁止されます。 。

これらのバスの動作メカニズムは、すべてのプロセッサのメモリへのアクセスをシリアル化して実行できます。どの時点でも、メモリにアクセスできるのは最大 1 つのプロセッサだけです。この機能により、単一バス トランザクション内のメモリ読み取り/書き込み操作がアトミックであることが保証されます。

一部の 32 ビット プロセッサでは、64 ビット データの読み取り/書き込み操作をアトミックにする必要がある場合、比較的大きなオーバーヘッドが発生します。この種のプロセッサを処理するために、Java 言語仕様では、JVM が 64 ビット長変数および double 変数の読み取り/書き込みのアトミック性を持つことを推奨していますが、必須ではありません。 JVM がそのようなプロセッサ上で実行される場合、64 ビット長/double 変数の読み取り/書き込み操作が 2 つの 32 ビット読み取り/書き込み操作に分割されて実行されます。これら 2 つの 32 ビット読み取り/書き込み操作は、実行のために異なるバス トランザクションに割り当てられる場合があります。このとき、この 64 ビット変数の読み取り/書き込みはアトミックではありません。

単一のメモリ操作がアトミックでない場合、予期しない結果が生じる可能性があります。下の図を見てください:

Java メモリ モデルの詳細な分析: 逐次一貫性

上の図に示すように、プロセッサ A が Long 変数を書き込み、プロセッサ B がこの Long 変数を読み取ろうとしているとします。プロセッサ A の 64 ビット書き込み操作は 2 つの 32 ビット書き込み操作に分割され、2 つの 32 ビット書き込み操作は実行のために異なる書き込みトランザクションに割り当てられます。同時に、プロセッサ B の 64 ビット読み取り操作は 2 つの 32 ビット読み取り操作に分割され、2 つの 32 ビット読み取り操作は同じ読み取りトランザクションに割り当てられて実行されます。プロセッサ A と B が上図のタイミング シーケンスに従って実行すると、プロセッサ B には、プロセッサ A によって「半分書き込まれた」だけの無効な値が表示されます。

上記は Java メモリ モデルの詳細な分析です: 逐次一貫性の内容 さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

PHP対Python:違いを理解します PHP対Python:違いを理解します Apr 11, 2025 am 12:15 AM

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHP:Web開発の重要な言語 PHP:Web開発の重要な言語 Apr 13, 2025 am 12:08 AM

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

未来を創る: まったくの初心者のための Java プログラミング 未来を創る: まったくの初心者のための Java プログラミング Oct 13, 2024 pm 01:32 PM

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。

See all articles