同期以来、「普遍的」であり、なぜ我々は、揮発性、それが必要なのでしょうか?

神の道へのJavaエンジニアのGitHubの6.6kスター、それについて知って来ないのですか?

神の道へのGitHubのJavaエンジニアの6.6kスターは、本当にそれを見ませんか?

神へのJavaエンジニアの道のGitHub 6.6kスターは、実際にそれについて知っていないと判断しますか?

私のブログや公共の数では、並行プログラミングに関する多くの記事を発表し、前回の記事では、我々は二つのキーワードでのJava並行処理でより重要な2を導入しました:同期と揮発性

私たちは、簡単に関連するコンテンツを確認してください。

1、原子の存在によって複雑解決するためには、Javaプログラミング言語、可視性と秩序の問題、および、そのような同期化、揮発性、最終的に、concurrenバッグなどの並行処理に関連するキーワード、の範囲を提供しています。そして、誰かが彼に発行された記事を入れてどのようなJavaのメモリモデルあなたを尋ねました

図2に示すように、溶液として使用することができる3つの特性が「ユニバーサル」であるように見える場合、それはアトミック、注文視認性を必要とするような方法をロックすることによって同期化。確かに、同時実行制御操作のほとんどは同期使用して行うことができます。そして、誰かがそう、彼に発行した記事を置く同期何をお願いします。

。3、可変の揮発性の様式の操作の前と後の揮発性メモリバリアを挿入することにより、同時かつ秩序変数下シーンの視認性を確保します。そして、誰かが記事はまた、彼に送られたということである揮発性のものをお願いします

図4に示すように、揮発性のキーワードは、アトミック性を保証し、そしてmonitorenterによって同期及び2つの命令は、それがマルチCPUタイムスライスに発生しない保証するためにのみ、同一の時間に1回のスレッドにアクセスできることが修正されたコードを確実に同期させることができるmonitorexitができませんスレッドの切り替え、アトミック性を保証することができます。エンドでのマルチスレッドのJava並行プログラミングは、それが子供たちがどのようにでしょうか?

さて、私たちが知っている、可視性、同期および揮発性の2つのキーワードが頻繁に使用される二つの重要なJavaの並行プログラミングされ、そして、前回のレビューでは、我々は知っている同期並行プログラミングはアトミックに表示されないことを保証することができ、 、問題を注文し、揮発性だけで視認性と秩序、そして保証することができ、両方のHE盛は、揮発性の同期生まれましたか?

同期の問題

それがロックされているので、我々はすべて、それが自然で、それが同期ロック機構の一種である知っている次のような欠点があります。

1は、パフォーマンスの損失があります

同期このような適応スピンロックの除去、ロック粗大化、軽量ロックとバイアスをロックする(よう、最適化の多くを行っにおけるJDK 1.6が、Java仮想マシン最適化されたロック-マルチスレッドの深い理解(5)技術)が、すべての後、彼はまた、ロックです。

(最適化のこれらのタイプの上に、すべてはモニター回避する方法を見つけることを試みる-原則Moniterの実現をマルチスレッドの深い理解(4) ロックされた、すべてではない場合でも、最適化した後、さらに最適化することができます)最適化プロセスは、一定の時間がかかります。

同期動作が必要とされた後、そのため、アンロック、同期ロックの前に実行される同期または同期ブロック法、または操作を使用するか、プロセスをアンロックこのロックは、パフォーマンスの損失を有することです。

多くの仮想マシンの排除による2間の性能比較、について、2間の性能差を定量化することは困難であるが、私たちは、基本的な原理を決定することができ、ロックの実装を最適化し、そうすることである:読み取り操作volatile変数のパフォーマンストランペット共通の変数が、メモリバリアを挿入する必要があるため、それはそうであっても、遅くなりますほとんど差はなく、書き込み操作ではありません、ほとんどのシーン中の揮発性は、ロックのオーバーヘッドよりも低くなっています。

閉塞をもたらす2、

で我々マルチスレッドの-depth理解(A) -の原則の実現同期同期方法や同期ブロックするかどうかを、同期させるために関連して導入された原則の実現を、またはそれがACC_SYNCHRONIZED monitorenterであるかどうか、monitorexitは、モニターの実装をベースとしています。

所有者の領域であるロックオブジェクトを獲得するスレッドがある場合には、複数のスレッドが同期コードのためにアクセスしたときにモニターのオブジェクトをベースに、最初のエントリーセットを入力します、他のスレッドは、エントリーセットを待ち続けます。そして時にスレッドがロックを解除し、待ちセット待ちを入力waitメソッドを呼び出します。

したがって、ロックは本質的には、複数のスレッドが同じ共有オブジェクトにアクセスキューにある、ブロッキング・ロックを達成同期されます。

揮発性は、Java仮想マシンが提供する軽量な同期メカニズムである、彼は達成するためにメモリバリアに基づいています。結局のところ、彼はロックされていなかったので、彼は同期による損失を遮断し、パフォーマンスの問題を持っていません。

揮発性の追加機能

揮発言及以前に加えて、私たちは、同期のパフォーマンスよりも優れ、揮発性のも、それはコマンド並び替え禁止されている素晴らしい追加があります。

のは、例を取るだけでどうなる揮発性の問題を使用せずに同期している場合を見てみましょう、我々はより身近シングルケース・モデルの実行を取りました。

私たちは、ダブルチェックロックの方法でシングルトンを達成、ここで揮発性のキーワードを使用しないでください。

 1   public class Singleton {  
 2      private static Singleton singleton;  
 3       private Singleton (){}  
 4       public static Singleton getSingleton() {  
 5       if (singleton == null) {  
 6           synchronized (Singleton.class) {  
 7               if (singleton == null) {  
 8                   singleton = new Singleton();  
 9               }  
 10           }  
 11       }  
 12       return singleton;  
 13       }  
 14   }  
复制代码

この操作がある、一度実行されます)あなたは一つのスレッドだけがコンテンツ同期コードブロック、そのシングルトン=新しいシングルトンを(実行することができ、同じ時間を確保することができ、ロックされて同期用いることで、上記のコードは、我々Singleton.classこれは、シングルトンを実装しています。

我々はコードで上述した実施形態の単一のオブジェクトを使用する場合しかし、ヌル・ポインタ例外が発生することが可能です。これはかなり奇妙な状況です。

私たちは、スレッド1とスレッド2は、2つのスレッドを同時にSingleton.getSingleton方法を要求したときにすることを前提としています。

STEP1、ライン8にスレッド1の実行は、オブジェクトを初期化します。ステップ2、スレッド2が5行目を実行し、それがヌル==決定シングルトンです。ステップ3、スレッド2は、裁判官の後にシングルトンを見つけました!= NULL、ライン12の実装ように、シングルトンを返します。ステップ4の後、スレッド2は、シングルトンオブジェクトは、()コールsingleton.callとして後続の操作を、実行を開始得ます。

上記のプロセスは、問題は思えませんでしたが、実際には、ステップ4、スレッド2でsingleton.callを呼び出すとき()、およびnullポインタ例外をスローすることが可能です。

ステップ3、スレッド2は、シングルトンオブジェクトは、完全なオブジェクトではありません得るため、すべてのは、NPEの外にスローされます。

私たちは分析するためにここにいる、シングルトン=新しいシングルトン();何かをする最後にこのコード行は、おおよそ次のように:

1、クラス参照のシンボルを見つけるために、新しい仮想命令、定数プールへの機会。2、シンボリック参照が表すクラスは、ロードされ解析され、初期化されているかどうかをチェックします。図3に示すように、仮想マシンのメモリをオブジェクトに割り当てられました。4、ゼロ値に初期化すべてに割り当てられた仮想マシンのメモリ空間。5、必要な設定をターゲットにする仮想マシン。6、実装方法は、メンバ変数が初期化されます。図7に示すように、オブジェクトのメモリ領域への参照。

我々は3つのステップに簡略化され、このプロセスが簡略化されて見てください:

、JVMは、メモリオブジェクトM bを割り当て、メモリMシングルトン変数にコピーアドレス、メモリM内のオブジェクトを初期化cは

ヌル裁判官は常に真となっている工程の前に、スレッド2は、シングルトンのために==、その後、彼はブロックされていたであろうスレッド1ので、シングルトン変数に割り当てられたメモリアドレスは、最後のステップであるため、このステップでは、スレッド1まで実行されます仕上げ。

しかし、上記のプロセスは、アトミック操作ではなく、上記の手順をに再配置される場合、コンパイラは、並べ替えることができます。

、JVMは、メモリシングルトン変数Bにコピーアドレスを、メモリオブジェクトM Cを割り当て、メモリM内のオブジェクトとして初期化されます

この場合、スレッド1は、オブジェクトを初期化する最初の実行中にメモリ割り当て、変数の割り当てを行い、最後に実行されます、そして、それはスレッド1がオブジェクトを初期化していないとき、言うことです、スレッド2は== nullは、事前に取得することが判定シングルトンに来ます偽彼は初期化を完了していないので、それは不完全なsigletonオブジェクトを返します。

この問題が発生したら、それは可能性が高いNPE例外であるとき、このオブジェクトを使用しようとすると、我々は不完全なシングルトンオブジェクトを取得します。

だから、どのようにこの問題を解決するには?命令再配置が問題につながるので、ライン上の命令の再配置を避けるだろう。

揮発性が命令再配置を回避するのでので、揮発性は、便利です。限り、コードに次のコードのように、我々はこの問題を解決することができます。

 1   public class Singleton {  
 2      private volatile static Singleton singleton;  
 3       private Singleton (){}  
 4       public static Singleton getSingleton() {  
 5       if (singleton == null) {  
 6           synchronized (Singleton.class) {  
 7               if (singleton == null) {  
 8                   singleton = new Singleton();  
 9               }  
 10           }  
 11       }  
 12       return singleton;  
 13       }  
 14   }  
复制代码

揮発性のシングルトンの使用上の制約、彼の指示の初期化プロセスが再配置されないことを確実にします。

秩序の保証を同期?

友人は、なぜここでそれはないだろう、上記のすべての問題の後、尋ねるや問題を命じ、それはそれの秩序を確保するために同期させることができると言うことではないでしょうがあり、ここを参照してください?

まず、ポイントは明確である:同期化は、プロセッサ命令再配置と最適化を禁止されていませんその後、彼はそれの秩序を確保する方法ですか?

そして、これは少し長く発注の概念を拡張します。自然順序付けでJavaプログラムは、一つの文にまとめることができます:あなたはこのスレッドを見ると、すべての操作は、自然と秩序あります。あなたは、スレッド内の別のスレッドを見れば、すべての操作は順不同です。

この文は原文では「Java仮想マシンの深い理解」よりですが、それを理解するためにどのように?周志明なし詳細説明。ここで私はこの事実の単純な拡張を見て、および関連など-IF-シリアルセマンティクス。

AS-IF-シリアルセマンティクスの意味を指し:どんなに並べ替え、シングルスレッドプログラムの結果が変化しないことをされていません。とにかくコンパイラやプロセッサの最適化は、AS-IF-シリアルセマンティクスを遵守しなければなりません。

セマンティクスを詳細にレイアウトするよう-IF-シリアルシングルスレッドは、どんなに命令再配置、インプリメンテーションの最終結果を変更することはできませんことを保証するために、そのままであれば、シリアルセマンティクスここで、それは単に、ではありません。

だから、私たちは二重のビューのシングルスレッドのポイントを立って、ロックを確認する例に戻って、それは、コンパイラがAS-IF-シリアルセマンティクスに準拠していますので、それを見スレッド1であるので、この最適化は何の問題もありません、このスレッドの実装の結果については何の効果もありません。

しかし、命令の内部転位がスレッド1スレッド2の影響を伝えます。

そこで、我々は秩序がつまり、複数のスレッド間の秩序を保証するために同期ために、複数のスレッドによって実行されるようにコンテンツをロックされていると言うことができます。しかし、その内部同期コードや並べ替えが行われますが、コンパイラやプロセッサは、以下のため、そのままであれば、シリアルセマンティクスので、我々は、これらは、単一のスレッド内で並べ替えを無視することができると言うことができます。

概要

本論文では、揮発性とかけがえのない二つの側面の重要性について説明します。

一つの理由は、ロック機構が同期されていることを、そこに、ブロッキングとパフォーマンスの問題が、揮発性がロックされていないので、ブロッキングとパフォーマンスの問題です。

一方、彼らの可視性と秩序の問題を解決するための障壁によって、揮発性メモリなぜなら、およびメモリバリアの使用もその添付ファイルdisableコマンドの再配置をもたらしますので、いくつかのシナリオで回避することができます問題は、命令の再配置で発生します。

おすすめ

転載: juejin.im/post/5d5c9fbce51d4561cd246641