JVM仮想マシンノートスレッドと<7>メモリモデル

Javaのメモリモデル

メインメモリとワーキングメモリ
のJavaメモリモデルの主な目的:プログラムのアクセスルールは、変数、すなわち、メモリに格納された仮想マシン内の変数とメモリから削除このような変数の基本的な詳細を定義します。ここで変数(変数)は、Javaプログラミング若干異なる変数にインスタンス変数/静的フィールドとオブジェクトを構成する配列要素、(スレッドのプライベート)ローカル変数およびパラメータを含まない方法を含みます。より優れた実行性能を得るために、Javaメモリモデルを交換するために、プロセッサとメインメモリを使用して特定のレジスタやキャッシュエンジンを実行するために限定されないが、それはまた、そのような権利を調整するタイムコンパイラコードの実行順序に限定されるものではありません。 

すべての変数は、(仮想マシンのメモリの一部)にメインメモリ(メインメモリ)に格納されているJavaのメモリモデルを指定します。各スレッドは、独自のワーキングメモリ(作業記憶)が、メインメモリのコピーのコピーを保存するためのメモリを作業のスレッドがワーキングメモリ内になければなりません(などの読み取り/割り当て、)変数上のすべての操作をスレッド、スレッドの変数に使用されています行われるが、直接メインメモリ変数を読み書きません。異なるスレッド間で直接他の変数のワーキングメモリにアクセスすることができない、スレッド間で渡される変数の値は、メインメモリの両方で行われる必要があります。

ここで、メインメモリ/作業メモリおよびJavaのJavaスタック/ヒープ/メソッド領域のメモリ領域は、メモリ分割の同じレベルではありません。アソシエーションの両方を強制する必要がある場合は、メインメモリから定義された変数/ /スタックの一部の領域に仮想マシンにメモリ対応するワーキングワーキングメモリ、メインメモリ、Javaヒープ・オブジェクトのインスタンスに対応する主データ部分を表示。低いレベルから、メインメモリは、ハードウェアのメモリであり、よりよい計算速度を得るために、仮想マシンとハードウェアシステムは、ワーキングメモリの優先度は、レジスタやキャッシュに格納されるかもしれません。

メモリとの間の相互作用
メインメモリとワーキングメモリとの間の特定の対話プロトコル、すなわち、どの変数コピーメインメモリから作業メモリに、実装の詳細等をメインメモリ同期バックからワーキングメモリ、Javaメモリー・モデルは、以下の8つを定義:完全に操作
ロック(錠):メモリ内の主な変数の役割は、現在のスレッドにプライベートとしてマークされた変数のメインメモリは、他のスレッドは、スレッドの排他的状態として識別変数にアクセスすることはできません。
ロック解除(アンロック):メインメモリの変数の役割は、変数がロック状態にある他のスレッドによってロックされるために、放出されます。
リード(READ):メインメモリに影響を与える変数は、変数の値は、その後の使用のロード操作のために、スレッドの作業メモリにメインメモリから送信されます。
荷重(負荷):ワーキングメモリ内の変数に影響を与える、メモリ内の変数の作業コピーにメモリから取得した変数の値の読み出し動作。
:使用(使用)は、仮想の出会いは、バイトコード命令は、変数の値を使用する必要があるたび、変数エンジンを実行するためにメモリの値を渡し、ワーキングメモリで動作している変数の操作を実行します。
Assgin(割り当て):ワーキングメモリから受信するワークメモリ上の変数演技の値、実行エンジンが変数に割り当てられ、この操作は、変数代入仮想遭遇バイトコード命令毎に行われます。
店舗(店舗):ワーキングメモリ内の変数に影響を与えるが、ワークメモリ内の変数の値は、その後の使用のために、メインメモリへの書き込み動作に転送されます。
ライト(書き込み):メインメモリに影響を与える変数、ワーキングメモリ変数にメインメモリから得られる可変ストア操作の値。

変数はワーキングメモリにメインメモリからコピーされた場合、読み取りおよびロード動作が順次行わ、可変同期ワーキングメモリからメインメモリへのバック、および順次格納書き込み操作を実行した場合。:Javaのメモリモデルはまた、8つの基本操作を説明した上で、実行時に満たされなければならない。次の規則を提供して
読み、ロード、ストアおよび書き込み操作は、メインメモリから変数の読み取りを許可していませんが、ワーキングメモリを受け入れない別に1を、発生しないようにしてくださいを、またはメインメモリの書き込みが、ワーキングメモリが戻って開始することから、状況は受け入れられません。
スレッドが戻ってメインメモリへの変更を同期するために必要なワーキングメモリ内の変数の変更後に、その最も最近の割り当ての動作、すなわちを破棄することはできません。
これは、スレッドがメインメモリにない理由(任意のアクションを割り当てないで起こる)ワーキングメモリスレッド同期バックからのデータではないことはできません。
実行は変数を使用して格納することである前にメインメモリ内の新しい変数がメモリにのみ、直接(負荷またはアサイン)作業を初期化されていない変数を使用することを許可されていない「生まれる」ことができ、あなたが最初に実行されて割り当てる必要がありますし、ロード操作。
一つだけのロックを操作するスレッドが、ロック操作を繰り返しロックした後、スレッドで複数回繰り返すことができる可能にすると同時に変数、ロック解除操作のみの同じ数を行い、変数のロックが解除されます。
あなたは変数にロック操作を行う場合は、ゾンビこの変数を使用する前に、実行エンジンに、この変数のワーキングメモリ値をクリアするには、我々は再実行する必要がありますまたは割り当て値のロード操作は、変数を初期化します。
変数は、以前ロック操作をロックされていない場合は、生きて別のスレッドによってロックされている変数のロックを解除するために許可されていないロック解除操作を実行することはできません。
変数に対してロック解除操作を実行する前に、メインメモリ(実行ストアと書き込み動作)可変なければならない最初の同期バック。

特別なルールのための揮発性型変数

volatileキーワードは、Java仮想マシンが提供する最も軽量な同期メカニズムであると言うことができます。
変数がvolatileとして定義されている場合、それは二つの特徴があります:
最初は、すべてのスレッドの可視性を確保することであるとき、スレッドの修正この変数の値は、他のスレッドのための新しい値があることを「可視性」とは、それはすぐに習得することができます。

揮発性変数に関する可視性誤解:「揮発性変数はそう、揮発書き込み動作上のすべての変数がすぐに他のスレッドに反映させることができる、換言すれば、各スレッド内の揮発性変数は同じであり、すべてのスレッドに直ちに表示されvolatile変数の計算に基づいて同時実行の下に「安全です。、その文の引数が間違っていないですが、その引数が続かない、この結論「操作volatile変数に基づいて、同時性の下で安全です」。
volatile変数volatile変数は、各スレッドにおけるワーキングメモリに矛盾することができます(一貫性の各スレッドのワーキングメモリ内に存在するが、それぞれの使用がリフレッシュする前に、一貫性のない実行エンジンは表示されません。状況は、)何の矛盾が存在しないと考えられるが、Javaの動作の内、安全でないとして、並行して運用volatile変数につながる、アトミック操作ではありません。

 

javapで逆コンパイル、コードの中で、「++レース」インクリメント操作で発生するが、クラスファイルのバイトコードのコードの一行だけの増加()メソッドを発見した問題点は、4つの命令(リターン命令がレースによって生成されていないから成り++この命令)が計算されないことが、容易にバイトコードレベルの同時故障の原因から:値は、この時点でキー揮発性レースの値が正しいことを確認するために、スタック動作にレースをとる場合getstatic命令これらの命令をIADDときには、実行iconst_1でで、他のスレッドがスタックの動作の値は古いデータになりながら、そうputstatic命令は、レースの実行後に小さな値を入れるかもしれませんが、レースの値を増加していることメインメモリに戻って同期します。

でも一つだけの命令をコンパイルし、それがこのディレクティブの実装はアトミック操作であることを意味するものではありませんので、客観的に言って、同時実行の問題を分析するためにバイトコードを使用して、この時点では、まだ、厳格ではありません。:本明細書で-XX使用されるコンパイラの実装、バイトコード命令は、ネイティブマシンコード命令のいくつかの部分に変換することができる場合に実行説明、説明は、そのセマンティクスを実装するコードの多くの行を実行するバイトコード命令逆コンパイルのいくつかを分析するための+ PrintAssembly出力パラメータは、より厳格になります。

volatile変数の可視性のみを保証するため、シーンには次の2つの規則に準拠していない計算で、我々はまだロックを渡す必要が(またはjava.util.concurrentの同期アトミッククラスを使用して)原子性を確保するために:

1)演算結果は、変数の現在の値に依存しない、または値は、単一のスレッドの変数を変更することを確保することができます。

2)変数は、他の状態変数一定の制約に参加する必要はありません。

最適化を禁止二リオーダー命令のセマンティクスを使用して揮発性変数、コモン変数が代入の結果にのみ依存しているすべての場所は、メソッドの実行中に得られた結果を修正することができることを保証しますが、順序は保証できませんが、変数の割り当てプログラムコードの実行の一貫性のため。方法スレッドの実行中(WithinThreadとして-IF-シリアルセマンティクスに記載のJavaメモリ・モデルは、いわゆる「シリアルセマンティクス用雌ねじ性能」であるこの点を認識することができないため )。

選択多くの同時保護安全ツールで揮発性の意味:ロックを優先する(またはロックの内側にsynchronizedキーワードjava.util.concurrentパッケージを使用)して実際にいくつかのケースでは、同期メカニズムのパフォーマンスは揮発性が、仮想マシンのために多くの除去とロックの最適化実現のために、それが困難に高速同期に比べになると信じてどのくらいの揮発性の定量化すること。消費及び一般的な性能変数が操作揮発性変数はほとんど差がないで読み取り、それが発生しないため実行処理を確実にするためにローカル・コードに挿入されたメモリ・バリア命令の多くを必要とするため、書き込み動作は、遅くてもよいです。そうであっても、トータルコストはまだロックより低い最も揮発性の高いシナリオで、私たちは、揮発性および揮発性ロックの中から選ぶだけで根拠は、シーンのニーズを満たすことができるだけの意味です。

volatile変数のための特別なルールのJavaメモリモデルが定義されました負荷、使用、割り当て、店舗及び書き込み動作は、次の規則を満足する必要がある場合、次に読み出しを行う揮発性変数を表し、Tは、スレッド、V及びWを表すと仮定する。

1)変数Vに前のアクションスレッドTを使用することを実行するために場合、負荷、T Vを行っている場合にのみ、T Vアクションがロードを実行するために、使用時、T V実行された後にのみ、および。V、およびT負荷のTの使用はV.のために考慮することができます 関連するアクションを読んで、(このルールはワーキングメモリを必要とし、それぞれの使用は、他のスレッドがV修正の値を見ることができることを保証するために、メインメモリVの開始前に、最新の値を更新する必要があります)行にまとめて表示される必要があります。

2)Tの前のアクションはASSIGN V、実行する店舗のV Tである場合にのみ、および、T動作はストアVで実行された後にのみ、V Tに割り当てる実行します。V T及びTストアはVに考えることができる割り当てるために、書き込み仲間は一列に一緒に表示されなければならない(このルールはワーキングメモリを必要とする、各修飾Vは直ちに他の保証のために戻ってメインメモリに同期されなければなりませんスレッドには、Vの)に独自の変更を見ています。

3)操作Aは、操作FがPであり、Fは、Vの読み取りまたは書き込み動作に対応する作用操作を想定し、アクションA関連するロードまたはストア動作であると仮定すると、使用または割り当て操作のV形態にTであると仮定する。等、Bは、操作のTまたはWの使用割当の実施例の動作と仮定され、そしてGは、操作ロードまたはストア動作は動作Bに関連付けられ、そしてQは、アクションが読み取りまたは書き込み操作の操作G Wに対応することが想定されているものとします。Bの前にA場合、Q前Pは(このルールは、揮発性変数は、命令がプログラムコードを確実にするために実行並べ替えることが最適ではないことを要求します)。

longとdouble型の変数のための特別な規則

64ビットのデータタイプ(長い二重)仮想マシンが揮発性読み出し動作は2つの32ビット演算に分割されて修正されない可能仮想マシンの実装は、64ビットデータロードの種類を選択することが保証されないことが可能にする、実行され、店舗、読み取り、および4つのアトミック操作を書き込み、それが非契約長い原子と二重(二重と長い変数のアトミック処理)の点です。

複数のスレッドが長いまたはdouble型の変数のような揮発性宣言し、読み、操作を変更するには彼らのために同じ時間に、そしていくつかは、非元の値であるスレッドを読むかもしれない、またそれは価値を修正し、他のスレッドの代表である共有している場合値「半タグ」。

しかし、仮想マシンが長く読まないと、二重の変数はアトミック操作として実装可能にしながら、「半分変数」と、このような読者は、(現在の商用VMに表示されていない)ため、Javaのメモリモデルは非常に稀であるところが、仮想マシンは、これらの操作を選択するために実装できますがアトミック操作であるが、これを達成するための仮想マシンを「強く推奨しました」。

アトム、視認性と秩序

アトミック(原子性):直接アトミック変数の動作を保証するためのJavaメモリモデルによっては、構成の読み取り、ロード、割り当て、使用、保管、および書き込みを、私たちは、一般に、アクセスの基本的なデータ型は(longとdouble例外)の原子を含んでいると考えることができます。

アプリケーションシナリオは、より大きな範囲をアトミック保証が必要な場合は、Javaのメモリモデルは、仮想マシンは、ユーザーに直接開いたロックとロック解除の操作にいないにも関わらず、会うの需要へのロックとロック解除の操作を提供しますが、言葉のより高いレベルを提供しますバイトコードmonitorenterと暗黙これら2つの操作を使用してmonitorexit命令、Javaのバイトコード命令コードの両方は反応シンクブロックは、キーワードを--synchronizedで動作も同期ブロックの原子との間に設けられています

視認性(可視性):スレッドが共有変数の値を変更するとき、他のスレッドがすぐにこの変更を認識することができることをいいます。

加えて、揮発性、Javaは、視認性を達成するために2つのキーがあり、同期および決勝視認性「(店舗および書き込み動作が実行される)変数は、バックメインメモリに同期されなければならない、可変にロック解除操作を実行する前に、シンクブロックによって決定される:このルールによって得られた最終的なキーワード手段の視認性」によって最終的に修正されたフィールドは、コンストラクタで初期化され、コンストラクタは「this」参照が出て合格しなかったら(このリファレンス・エスケープは、非常に危険なものである「初期の半分にこの参照を通じてアクセスすることができ、他のスレッドがあります「オブジェクト)、その後、他のスレッドは、フィールドの最終値を見ることができます。

秩序(オーダー): Ifはこのスレッドで表示、すべての操作が並べられ、スレッド内の別のスレッド場合は、すべての操作を観察:言葉の自然な順序でJavaプログラムはように要約することができます。彼らは乱れています。最初の語句「シリアルセマンティクスの症状スレッド」を指す(内スレッドとして-IF -シリアルセマンティクス)、 ワード手段「命令並べ替え」現象と「ワーキングメモリとメインメモリの同期遅延」現象後。

Java言語は、揮発性とスレッド間の秩序ある動作を保証するために、同期二つのキーワードを提供し、揮発性のキーワード自体が意味を並べ替え禁止命令が含まれていますが、それが唯一同時に許可変数」から同期されますその動作「ルールが取得されたロックスレッド、ルールは決定のみシリアル入力することができる2つの同期ブロックとロックを保持しています。

最初の発生原理

動作は、第1のA操作Bで発生した場合」、観察された生成動作Bが発生する前に、動作はA、Bの動作に影響を与えることができることを、実際には、Java(登録商標)メモリ・モデルで定義された2つの操作の間の第1の部分的順序関係を発生効果は、「メモリ/メッセージ送信/呼び出されたメソッドでは、共有変数の値を変更することが含まれます。

ここではいくつかの「自然」の関係は、最初にどのような援助同期がすでに存在せず、コードで直接使用することができ、Javaのメモリモデルの下で起こっています。二つの操作間の関係が表示されていない、そして次の規則を押し出すことができない場合は、順序の保証はありません、仮想マシンは、自由に並べ替えることができます。

1)プログラム・シーケンス・ルール(プログラム順序ルール):スレッドで、コードブックEDITORIAL書き込み動作のプログラム順序によれば最初の操作後に発生します。むしろ分岐/ループ構造として考慮されるべきプログラムコードの順序、より正確に制御された流れであるべきです。

2)チューブロックルール(モニタロックルール):最初のロック解除操作が発生し、ロック操作では、後で同じロックに直面しています。ここでは、同じロック、および「裏」は、時間の順序を参照することを強調しなければなりません。

3)揮発性変数ルール(volatile変数ルール):揮発性変数への書き込みは最初の「背後」は時間順序を指す読み出し動作後、この変数の面で発生しました。

4)スレッド開始ルール(スレッドスタートルール):スタートこのスレッドにおけるスレッドオブジェクト()メソッドが最初に出現するすべての動き。

5)スレッド終了規則(スレッドの終了ルール):すべての操作が先にスレッドの終了のです。このスレッドの検出で発生し、我々はThread.join()メソッド/Thread.isAlive()の戻り値で終了することができ、他の手段によって検出されました郡は終了しました。

6)(中断ルールスレッド)スレッド割り込み正規:呼び出すスレッド割り込み()メソッドは、最初の割り込みイベントに割り込まれたスレッドコード検出で発生した割り込みが発生した場合Thread.interrupted()メソッドによって検出することができ、発生します。

ルールオブジェクト(ファイナライザルール)の7)終了:オブジェクトの初期化は、最初に起動し、そのファイナライズ()メソッドで発生した(コンストラクタ実行終了)を完成します。

8)推移(推移):動作が先にA手順Bを発生した場合、Bの先行操作が操作Cで発生し、動作は、第1の操作A Cで発生します

 発生順の最初の時間は、基本的な原理の間にあまり関係ありませんので、我々は干渉年代同時セキュリティ上の問題を測定していない、すべてが最初に出現したの原則に従わなければなりません。

Javaスレッド

並行処理はマルチスレッドに必ずしも依存しないが、Java並行処理、スレッドの最も避けられない関係について話があり。

スレッドを実装

主流Caozuojitongは、Java言語では、同じプロセスとCaozuojitong異なるハードウェアプラットフォームでスレッドを提供し、スレッドの実装を提供し、java.lang.Threadのクラスの各インスタンスは、スレッドを表します。ThreadクラスとJava APIのほとんどは、キーのすべてのメソッドがネイティブであると宣言され、有意差を持っています。ネイティブメソッドは使用しなくてもよいか、それは、Java APIでこの方法を意味達成するために、プラットフォームに依存しない手段を使用することはできません。このような理由から、我々は代わりに「スレッドを達成するために、」ここにいる「を達成するためにJavaスレッド。」

実装スレッドは、3つの主要な方法があります。

1.カーネルスレッドの実装

カーネルスレッド(カーネルスレッド、KLT)は、このスレッドは、カーネルスレッド切り替えによって完成され、(以下、コアと呼ばれるカーネル、)オペレーティングシステムのカーネルサポートスレッドによって直接あり、スケジューラ(スケジューラ)を操作することによって、カーネルスレッドのスケジューリング、および責任がありますスレッドのタスクは、各プロセッサ上にマッピングされました。オペレーティングシステムは、同時に複数の事、マルチスレッドのマルチスレッドカーネルと呼ばれるカーネル(マルチスレッドカーネル)のサポートを処理する能力を持っているように、各カーネルスレッドは、予備のコアとして見ることができます。

プログラムは、一般的にカーネルスレッドに直接移動しませんが、カーネルスレッドへの先進的なインターフェースを使用する- LWP(ライトウェイトプロセス、LWP)、我々はスレッドの通常の意味での話という軽量プロセスに起因します各コースは、軽量カーネルスレッドのサポートで構成された軽量プロセスを持っているために、これだけ第一支持カーネルスレッド、。この軽量プロセスとカーネルスレッド間の1:1の関係は、1スレッドモデルと呼ばれます。

軽量プロセスの制限は:それは達成するためにカーネルスレッドに基づいているため、そのような創造/破壊や同期などの処理動作、さまざまなので、我々は、システムコールを必要とします。システムコールの比較的高いコストは、ユーザーモード(ユーザーモード)とカーネルモード(カーネルモード)で前後に切り替える必要があり、各軽量プロセスをサポートカーネルスレッドを持っている必要があり、軽量のプロセスは、したがって消費する必要がありますいくつかのカーネル(たとえば、カーネルスレッドのスタック領域など)のリソース、およびそのためのシステムは、軽量プロセスが限定されているサポートしています。

2.ユーザースレッド実装

ユーザースレッド狭義にはユーザ空間スレッドライブラリに完全に指し、カーネルはスレッドが存在する実装に知覚できません。ユーザーモードで完全に行われたユーザスレッド/同期/破壊やスケジュールを作成するには、カーネルが助けを必要としません。プログラムが適切に実装されている場合は、このスレッドは、カーネルモードに切り替える必要がないので、高速動作と低消費は、ユーザスレッドで実装された高性能データベースマルチスレッドの一部では、より多数のスレッドをサポートすることができます。このプロセスは、ユーザスレッド1:Nの関係は、スレッドモデル対多と呼ばれます。

3.軽量のユーザースレッドに加え、ハイブリッド実装プロセス

両方のユーザスレッドがあり、また、軽量プロセスがあります。

 

Javaスレッドのスケジューリング

スレッドのスケジューリングは、割り当てプロセスのスレッドプロセッサの使用権のためのシステムです。主な方法のスケジュール:

マルチスレッドシステムを使用して協調スケジューリングは、実行時間のスレッドは、スレッド自体によって制御され、積極的にシステムに通知するために自分の仕事を行った後、スレッドが別のスレッドアップに切り替わります。長所:シンプル。短所:実行時間を制御することができません。

システムにより、各スレッドの実行時間をプリエンプティブマルチスレッドシステムコールを使用して、スレッド切り替えスレッド自体が助けを決めていません。Javaはこのスレッドのスケジューリングを使用しています。

Javaはスレッドの優先度の10のレベルを提供するJavaスレッドがスレッドスケジューリングが最終的にオペレーティング・システムによって決定されるので、実装ネイティブスレッドシステムにマッピングされているので、しかし、スレッドの優先順位は、飛んでいません。

状態遷移

Java言語は、定義の5種類のスレッドが唯一の、唯一の状態を持つことができ、時間のいずれかの時点で、プロセスの状態を:

新(新):この状態で開始されていないスレッドを作成します。

ファイル名を指定して実行(Runable):オペレーティングシステムのスレッド状態が実行と準備を含むが、このスレッドの状態で実行してもよいし、それに割り当てられたCPUの実行時間を待つことができます。

(待機)無期限に待機:スレッドがCPUの実行時間を割り当てられません。この状態になっている、彼らはディスプレイをウェイクアップするために、他のスレッドを待ちたいです。以下の方法は、無期限の待機状態にスレッドになります。

タイムアウトパラメータははObject.wait()メソッドで設定されていません。

Timeoutパラメータは、Thread.join()メソッドを設定されていません。

LockSupport.park()メソッド。

待機期間(時限待機):スレッドが、他のスレッドが、目を覚ます一定時間後に、システムによって自動的にウェイクアップするために表示されるのを待たずにCPUの実行時間を割り当てることができないこの状態にあります。以下の方法は、待機状態の期限にスレッドになります。

Thread.sleepに()。

パラメータTIMEOUTはObject.wait()メソッドを提供しました。

Thread.join()メソッドのタイムアウトパラメータセット。

LockSupport.parkNanos()メソッド。

LockSupport.parkUntil()メソッド。

(ブロック)ブロックされた:スレッドがブロックされている、「ブロック」と「待ち状態」の区別がある:排他ロックを取得するために待機で開催された「ブロック」、このイベントは、ロック時間を放棄するために、別のスレッドになります。」待機状態は、「いくつかの時間を待っている、またはウェイクアクションが行われます。プログラムは、エントリ領域シンクブロックを待っているに進むと、スレッドはこの状態になります。

エンド(終端):終了したスレッドのスレッド状態、スレッドが実行を完了しました。

おすすめ

転載: www.cnblogs.com/lvoooop/p/12132984.html