ホームページ  >  記事  >  Java  >  Java の volatile の高同時実行性の実装原理の詳細な紹介

Java の volatile の高同時実行性の実装原理の詳細な紹介

黄舟
黄舟オリジナル
2017-03-30 10:26:131429ブラウズ

この記事では、Java の高同時実行性の volatile の実装原理に関する関連情報を主に紹介します。Volatile は、マルチプロセッサで使用される軽量の同期化されたものです。共有変数の「可視性」は、開発中に保証されます。必要な友人は、

高同時実行における volatile の Java 実装原則を参照してください

要約: Synchronized と Volatile は両方ともマルチスレッド同時実行で役割を果たします。プログラミングの重要な役割である Volatile は、マルチプロセッサ開発における共有変数の「可視性」を保証する軽量の同期です。可視性とは、あるスレッドが共有変数を変更すると、別のスレッドが変更された値を読み取ることができることを意味します。場合によっては、同期よりもコストが低くなります

1. 定義:

java

プログラミング言語は、共有変数が正確かつ一貫して更新されることを保証するために、スレッドが次のことを確認する必要があります。排他ロックを介してこの変数を個別に取得します。 Java 言語には volatile が用意されており、状況によってはロックよりも便利です。フィールドが volatile として宣言されている場合、Java スレッド メモリ モデル は、すべてのスレッドがこの変数の同じ値を参照することを保証します

2. Volatile 実装の原則

それでは、Volatile はどのようにして可視性を確保するのでしょうか? x86 プロセッサでは、ツールを使用して JIT コンパイラによって生成されたアセンブリ命令を取得し、Volatile への書き込み時に CPU が何を行うかを確認します。

Javaコード:instance = new Singleton();//インスタンスは揮発性変数です

アセンブリコード:0x01a3de1d:movb $0x0,0x1104800(%esi);0x01a3de24:lock ad

dl $0x0,( % esp);volatile 変数で変更されたシェア変数を記述すると、アセンブリ コードの 2 行目が追加されます。IA-32

Architecture

ソフトウェア開発者マニュアルを確認すると、次のような命令が記述されていることがわかります。ロック プレフィックスはマルチコア プロセッサの下に追加されます。2 つのことが起こりました。 現在のプロセッサ

キャッシュ

ラインのデータがシステムメモリに書き戻されます。 このメモリへの書き戻し操作により、他の CPU のこのメモリ アドレスにキャッシュされたデータが無効になります。

処理速度を向上させるために、プロセッサはメモリと直接通信せず、操作を実行する前にまずシステム メモリ内のデータを内部キャッシュ (L1、L2 など) に読み込みます。操作が完了しても、いつメモリに書き込まれるかは不明です。宣言された Volatile 変数に対して書き込み操作が実行されると、JVM はプロセッサにロック プレフィックス命令を送信して、キャッシュ ラインにデータを書き込みます。変数はシステム メモリに戻されます。ただし、メモリに書き戻されたとしても、他のプロセッサがキャッシュした値が古いままだと、計算処理を実行する際に問題が発生するため、マルチプロセッサ下では各プロセッサのキャッシュを確保する必要があります。プロトコルが一致している場合、各プロセッサは、バス上にアップロードされたデータを傍受することによって、キャッシュされた値が期限切れになっているかどうかを確認し、そのキャッシュ ラインに対応するメモリ アドレスが変更されたことを検出すると、そのキャッシュ ラインを変更します。現在のプロセッサのキャッシュ ラインは無効な

状態

に設定されています。プロセッサがこのデータを変更したい場合、システム メモリからプロセッサ キャッシュにデータを再度読み取ることが強制されます。 ロックプレフィックス命令により、プロセッサキャッシュがメモリに書き戻されます。 Lock prefix 命令により、命令の実行中にプロセッサの LOCK# 信号がアサートされます。マルチプロセッサ環境では、LOCK# 信号により、信号がアサートされている間、プロセッサが共有メモリを排他的に使用できるようになります。 (バスをロックしてしまい、他のCPUがバスにアクセスできなくなるためです。バスにアクセスできないということは、システムメモリにアクセスできないことを意味します。) ただし、最近のプロセッサでは、一般的にLOCK#信号はバスをロックしません。ただし、キャッシュをロックします。結局のところ、ロックはバスのオーバーヘッドが比較的大きいです。プロセッサ キャッシュに対するロック操作の影響については、第 8.1.4 章で詳しく説明します。Intel486 および Pentium プロセッサの場合、ロック操作中に LOCK# 信号が常にバス上でアサートされます。ただし、P6 以降のプロセッサでは、アクセスされるメモリ領域がプロセッサ内にすでにキャッシュされている場合、LOCK# 信号はアサートされません。代わりに、このメモリ領域のキャッシュをロックしてメモリに書き戻し、キャッシュ整合性メカニズムを使用して変更のアトミック性を確保します。この操作は「キャッシュ ロック」と呼ばれます。キャッシュ整合性メカニズムは、同時変更を防止します。 3 つ以上のプロセッサによってキャッシュされたメモリ領域のデータ。

1 つのプロセッサのキャッシュをメモリに書き戻すと、他のプロセッサのキャッシュが無効になります。 IA-32 プロセッサーとインテル 64 プロセッサーは、MESI (変更、排他的、共有、無効化) 制御プロトコルを使用して、内部キャッシュと他のプロセッサーのキャッシュの一貫性を維持します。マルチコア プロセッサ システムで動作している場合、IA-32 および Intel 64 プロセッサは、システム メモリとその内部キャッシュへの他のプロセッサのアクセスを盗聴する可能性があります。これらはスニッフィング技術を使用して、内部キャッシュ、システム メモリ、およびその他のプロセッサ キャッシュ内のデータがバス上で一貫性を保っていることを確認します。たとえば、Pentium および P6 ファミリのプロセッサでは、あるプロセッサがスニッフィングされて、現在共有状態を処理しているメモリ アドレスに別のプロセッサが書き込もうとしていることを検出すると、スニッフィング プロセッサは次のようにそのキャッシュ ラインを無効にします。同じメモリアドレスへのすべてのアクセス

以上がJava の volatile の高同時実行性の実装原理の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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