多くの友人は、キーワードが不安定であると聞いたことがあり、それを使用したかもしれません。 Java 5以前は、プログラムでそれを使用すると予想外の結果が得られるため、物議を醸すキーワードでした。 Java 5が揮発性のキーワードがその活力を取り戻した後にのみ。揮発性のキーワードは文字通り理解するのが簡単ですが、うまく使用するのは簡単ではありません。
1。序文
JMMは、可視性を確保するために、揮発性変数定義、最終的な同期ブロックを提供します。
揮発性で変更された変数の場合、スレッドは変数を使用するたびに変数の最も変更された値を読み取ります。揮発性は簡単に誤用され、原子動作に使用されます。私はいくつかのテスト例を書きました、あなたはそれを試してみることができます。
2。メインプログラム
public class main {public static void main(string [] args)throws arturnedexception {list <thread> threadlist = new ArrayList <shood>(); {single.holder.instance.add();}}); threadlist.add(thread); thread.start();} for(thread:threadlist)thread.join(); system.out.println(single.holder.instance.x);}}}3。シングルトンモードテスト
1.揮発性がなく、同期なし
class single {public int x = 0; public void add(){try {timeunit.milliseconds.sleep(50);} catch(arturnedextrace e){e.printstacktrace();} ++ this.x;} public static class Holder {public static single instance = new single();}}}出力の結果:8、9、および10がすべて表示されています。もっと実行してもっと試すことができれば、さまざまな結果が見つかります。
2。揮発性がありますが、同期はありません
class single {public volatile int x = 0; public void add(){try {timeunit.milliseconds.sleep(50);} catch(arturtedextrace e){e.printstacktrace();} ++ this.x;} public static class Holder {public static single inst = new single();}}}出力結果:発生の最大数は9および10です。
3.揮発性はありません、同期
class single {public int x = 0; public synchronized void add(){try {timeunit.milliseconds.sleep(50);} catch(arturnedextrace e){e.printstacktrace();} ++ this.x;} public static class Holder {public static single instance = new single();}}}}出力の結果:何回実行しても10になります。
4。DCLでの揮発性の適用について(再チェックロック)
パブリッククラスLazySingleton {private int somefield; private static lazysingleton instance; private lazysingleton(){this.somefield = new Random()。nextint(200)+1; //(1)} public static lazysingleton getInstance(){if(instance == null){//(2)同期(lazysingleton.class){//(3)if(instance == null){//(4)instance = new lazysinglonton(); //(5)}}} return instance; //(6)} public int getSomefield(){return this.somefield; //(7)}}まず第一に、この執筆方法がJavaで機能しない理由を説明させてください!
スレッドIが初めてgetInstance()メソッドを呼び出していると仮定し、スレッドIIはgetInstance()メソッドとgetomefield()メソッドも呼び出します。私たちが説明したいのは、スレッドI(1)のステートメントは、スレッドII(7)の前に発生していないということです。スレッドIIがgetInstance()メソッドのステートメント(2)を実行する場合、インスタンスへのアクセスは同期ブロックにないため、スレッドIIはステートメント(5)でインスタンスに書いているスレッドIの書き込みを観察する場合と観察しない場合があります。最初に、インスタンスの値が空ではないと仮定するので、そのスレッドがインスタンスを書き込むことを観察します。この時点で、Thread IIはステートメント(6)を実行し、このインスタンスの値を直接返し、このインスタンスでGetSomeField()メソッドを呼び出します。この方法は、同期なしでも呼ばれます。したがって、スレッドIIの操作全体が同期なしで呼び出されます。これは、スレッドIのステートメント(1)とスレッドIIのステートメント(7)の間に前の関係がないことを示しています。これは、スレッドIがステートメント(1)で微分されたスレッドIによって記述された値を観察できない可能性があることを意味します。これはDCLの問題です。それはばかげていますよね? DCLはもともと同期を逃れることを目的としており、この目標を達成しました。まさにこのために、最終的に罰せられました。そのようなプログラムには深刻なバグがありますが、そのようなバグが発見される可能性は間違いなく宝くじに勝つ確率よりもはるかに低く、つかの間です。さらに恐ろしいのは、それが起こったとしても、それがDCLによって引き起こされたとは思わないということです。
私の理解では、スレッドIとスレッドIIの両方に独自の作業ストレージがあります。スレッドがインスタンスを作成した後、メモリにリフレッシュする時間は不確かであるため、スレッドIがステートメント(1)でfileされたスレッドIによって記述された値を観察できない可能性があります。
したがって、Java 5に追加されたルールが追加されているため、追加の出来事があるからです。
•揮発性フィールドへの操作の書き込み - その後の読み取り操作が同じフィールドに操作する前に。
このルールを使用して、インスタンスを揮発性と宣言できます。つまり、私的揮発性の静的LazySingletonインスタンス。
この規則によれば、スレッドI(5) - >スレッドII(2)(つまり、スレッド)の文の文、単一スレッドルール、スレッドI(1) - >スレッドI(5)の文の文(2) - >文の文の文に従って、スレッドII(7)の文の文を取得できます。声明(1)に載っている人に、プログラムは正しい動作を得ることができます。
サプリメント:Java5の前に、最終フィールドの同期セマンティクスと他の変数の間に違いはありません。 JAVA5では、コンストラクターに最終変数が設定されると(この参照がコンストラクターに漏れていない場合)、他のスレッドはコンストラクターに設定された値を間違いなく表示します。 DCLの問題は、オブジェクトのメンバー変数のデフォルト値が表示されているため、LazySingletonのSomeField変数を最終的に設定して、Java5で正しく実行できるようにすることです。
上記のコンテンツは、編集者が紹介したJavaの揮発性キーワードの知識です。私はそれが誰にでも役立つことを願っています!