Java 同時プログラミングの揮発性および JMM マルチスレッド メモリ モデルの分析例
1. プログラムで現象を確認する
Java マルチスレッド キャッシュ モデルの説明を始める前に、まず次のコードを見てみましょう。このコードのロジックは非常に単純です。メインスレッドは 2 つのサブスレッド (スレッド 1 とスレッド 2) を開始します。スレッド 1 が最初に実行され、スレッド 2 は 2 秒間スリープした後に実行されます。 2 つのスレッドは、初期値が false の共有変数 shareFlag を使用します。 shareFlag が常に false の場合、スレッド 1 は常に無限ループになるため、スレッド 2 で shareFlag を true に設定します。
public class VolatileTest { public static boolean shareFlag = false; public static void main(String[] args) throws InterruptedException { new Thread(() -> { System.out.print("开始执行线程1 =>"); while (!shareFlag){ //shareFlag = false则一直死循环 //System.out.println("shareFlag=" + shareFlag); } System.out.print("线程1执行完成 =>"); }).start(); Thread.sleep(2000); new Thread(() -> { System.out.print("开始执行线程2 =>"); shareFlag = true; System.out.print("线程2执行完成 =>"); }).start(); } }
JMM スレッド モデルをまだ学習していない場合は、上記のコードを読んだ後、出力結果が次のようになることを期待しているでしょう。
スレッド 1 の実行を開始 =>スレッド 2 の実行を開始 => スレッド 2 の実行が完了 => スレッド 1 の実行が完了 =>
このコードは下図のように、普通の人なら理解できるコードなので、まずスレッド 1 を実行してループに入ります。 2 shareFlag=true を変更すると、スレッド 1 がループから抜け出します。したがって、ループから抜け出したスレッド 1 は「スレッド 1 の実行が完了しました =>」と出力されますが、筆者の実験後、**「スレッド 1 の実行が完了しました =>」は出力されず、スレッド 1 はループから抜け出すことはありません。無限ループ**。これはなぜですか?
2. この現象はなぜ発生しますか (JMM モデル)。
上記の問題を説明するには、JMM (Java Memory Model) Java メモリ モデルを学習する必要がありますが、Java マルチスレッド メモリ モデルと呼ぶ方が正確だと思います。
まず、JMM では、各スレッドが独自の作業メモリを持ち、プログラムが開始されると、スレッドは共有変数をロードします (read&load)。独自の作業メモリ内では、スレッドの作業メモリにロードされるメモリ変数は、メイン メモリ内の共有変数のコピーです。つまり、現時点ではメモリ内に shareFlag のコピーが 3 つあり、それらの値はすべて false に等しいということです。
スレッド 2 が
shareFlag=true
を実行すると、その作業メモリのコピーがshareFlag=true
に変更され、コピーの値は次のようになります。同時に同期され、メインメモリにライトバック(ストア&ライト)されます。しかし、スレッド 1 の作業メモリ内の
shareFlag=false
は変更されていないため、スレッド 1 は無限状態になります。ループ。中央。
3. MESI キャッシュ コヒーレンス プロトコル
スレッド 2 による共有変数の変更は、スレッド 1 には認識されません。これは、上記の実験結果と JMM と一致します。モデル。では、スレッド 1 は共有変数の値が変更されたことをどのように認識できるのでしょうか?実際、これは非常に簡単で、shareFlag 共有変数に volatile キーワードを追加するだけです。
public volatile static boolean shareFlag = false;
基本的な原理は次のとおりです。volatile キーワードを追加すると、JMM は MESI キャッシュ整合性プロトコルに従うように求められます。このプロトコルには、次のキャッシュ使用仕様が含まれています (理解できない場合は、無視してください。以下で使用します。簡単な言葉と例で説明してください)。
Modified: 現在のキャッシュ ラインのデータが変更 (ダーティ) されており、現時点では現在の CPU のキャッシュ内でのみ変更されていることを表します。 、キャッシュ行のデータは、他のキャッシュのデータやメモリ内の行のデータとは異なります。
Exclusive: 現在のキャッシュ ラインのデータが有効なデータであり、他の CPU のキャッシュにはそのようなデータ ラインが存在しないことを示します。現在のキャッシュラインのデータはメモリ内のデータと異なります。
Shared: このデータ行は複数の CPU を表すキャッシュにキャッシュされ、キャッシュ内のデータはメモリ内のデータと一致します。
Invalid: 現在のキャッシュ行のデータが無効であることを示します;
上記のキャッシュ 使い方の仕様が複雑すぎるかもしれませんが、簡単に言うと、
スレッド 2 が shareFlag を変更したとき (「変更」を参照)、共有フラグを変更したことをバスに通知します。変数 shareFlag,
スレッド 1 はバスを監視し、共有変数 shareFlag が変更されたことを知ると、作業メモリ内の shareFlag のコピーを削除して無効にします。
- #スレッド 1 が shareFlag を再度使用する必要があり、作業メモリに shareFlag 変数のコピーがないことが判明すると、メイン メモリからリロード (読み取り&ロード) されます
以上がJava 同時プログラミングの揮発性および JMM マルチスレッド メモリ モデルの分析例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック









Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

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

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

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

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

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