2012-03-15 14 views
2

Javaスレッドの揮発性キーワードの例が必要です。Javaにおけるvolatileキーワードの動作

volatileキーワードの定義によると、変数がvolatileとして宣言された場合、スレッドはローカルスレッドキャッシュからの読み書きの代わりに変数メモリへの直接の読み書きを行います。

私が間違っている場合は、私に修正してください。だから私は、以下のプログラムを実行することを理解する上で

public class ThreadRunnableBoth implements Runnable{ 
    private volatile int num =0; 

    public void run(){ 
     Thread t = Thread.currentThread(); 
     String name = t.getName(); 

     for(int i=0; i<100; i++){ 
      if(name.equals("Thread1")){ 
       num=10; 
       System.out.println("value of num 1 is :"+num); 
      }else{ 
       num=15; 
       System.out.println("value of num 2 is :"+num); 
      } 
     } 

    } 
    public static void main(String args[]) throws InterruptedException{ 
     Runnable r = new ThreadRunnableBoth(); 
     Thread t1 = new Thread(r); 
     t1.setName("Thread1"); 

     Thread t2 = new Thread(r); 
     t2.setName("Thread2"); 

     t1.start(); 
     t2.start(); 

    } 
} 

私はいくつかのサイトからこれらの例を持って、私はそれを実行しているしようとしたとき、私は、揮発性の取り外しやvolatileキーワードを追加する任意の違いを参照してください傾けます。

私はそれを削除して追加する際に違いが生じることをご説明ください。

ありがとうございます。

答えて

0

so キーワードvolatileがない場合、スレッドはローカルメモリキャッシュにnumの値を出力しているだけです。 numへの変更は、他のスレッドのビューnumとは決して同期しません。 volatile

value of num 1 is :10 
value of num 2 is :15 
value of num 1 is :10 
value of num 2 is :15 
value of num 1 is :10 
value of num 2 is :15 
... 

、彼らはセット/取得の周りのメモリバリアと同じグローバル保管場所への更新と印刷の両方である:私のような出力を参照してください。しかし、これは競争条件の影響を非常に受けやすい出力を変更することはありません。

value of num 2 is :15 
value of num 1 is :15 
value of num 2 is :15 
value of num 1 is :10 
value of num 2 is :15 
value of num 1 is :10 
... 

値が印刷されたときに最後に更新された設定間の競合があります:私は、出力は次のように参照してください。

プロセッサアーキテクチャまたはJREがIOイベントでのみコンテキスト切り替えを行っているか、またはフルスレッド実行を提供していないため、この出力が表示されないことがあります。あなたがいくつかの出力を表示する場合、私はいくつかの詳細をコメントすることができます。 volatileキーワードの定義に従って

0

それは変数がvolatileとして を宣言したとき、言う、スレッドは直接ローカルスレッドキャッシュからではなく、読み取り/書き込みの変数 メモリへの読み出し/書き込みます。

必ずしもそうである必要はありません。 cache coherenceをサポートしているシステムでは、メインメモリからの読み取りを行わずに最新のvolatileフィールドを使用することができます。 Volatileによれば、各スレッドは特定のフィールドの最新の値を参照します。

メモリの可視性については、volatileを削除してもプログラムが失敗すると思われる場合は、(すぐに)変更が表示されるとは限りません。それが長くなればなるほど、さらに多くの問題が発生します。

3

volatileキーワードの主な違いは、安全にデータを操作するためのメモリフェンスが必要かどうかです。

メモリフェンスは、アウトオブオーダー実行のために複数のスレッド間で発生する可能性のある副作用を防ぎます。 CPUに指示することによって、コンパイラ/実行時環境は、プログラムの正確性を損なうことなく、読取りに対する元の順序制約を操作できないことをCPUに伝えることができます。

Read up on memory fences hereであり、ソリューションの鍵は一貫性であることを覚えておいてください。ではありません。読み取り要求はキャッシュで停止することができ、キャッシュが(CPUの内部メカニズムによって)一貫性があることが保証されます。

0

multiprocessorシステムでは、異なるスレッドが異なるプロセッサで実行されるシステムでは、揮発性変数の影響が明らかです。通常のシングルプロセッサシステムでは、その影響は明白ではないかもしれません。

同じテーマのこのサイトのgood discussion threadです。

0

例では、numはデフォルト値の0で始まり、その宣言行で0に割り当てます。 numvolatileではない場合、その割り当てはデータ競争になりますが、もちろんその違いを伝えることはできません。

次に、1つのスレッドでnumを使用するだけです。スレッド内では、コードが示す順序で常に何かが発生します。この場合、numはvolatileである必要はありません。

今、あなたはあなたのmain方法を変更した場合、それはスレッドが開始した後t1.numを確認するように(しかし、それはThread.joinのように、事前発生エッジを作成する方法に仕上がっていることを確認せずに)、あなたはデータを持っているでしょうnumなしの競争は揮発性である。あなたはmainを5日間待つことができますが、それでもが0以外のものとして表示されることは保証されません。そしてThreadRunnableBothfalseを開始し、飛躍の終わりにtrueに設定されたことboolean不揮発性持っていたが、あれば、ということだけではなく、mainも見ることができるboolean(したがって、スレッドが終了していたという意味)trueとして、それでもnum0!これはデータ競合であり、numより前にブール値がローカルレジスタからフラッシュされるマルチコアマシンで(たとえば)発生する可能性があります。この例では、numとブール値volatileの両方を作成すると、booleanがtrueの場合はnum == 0 || num == 15になります。

しかし、ここでは、キッカーだ:でもvolatileキーワードを指定せずに - つまり、偶数データレースの存在下で - あなたがいない際どい動作を確認するためにを保証しています。つまり、データ競争は、あなたが別のスレッドで変更を見ることを保証できないと言いますが、そうしないと保証するものではありません。それはあなたのマシン上で100回もうまく動作するかもしれませんし、誰かがそれを野生の8コアマシンに置くと、それはより複雑なプログラムの一部なので、違った方法で最適化されてしまいます。

0

ほとんどの話はハードウェアに関するものです。実際には、コンパイラの最適化が一般に適切です。小規模な方法でフィールドに繰り返しアクセスしているので、それをレジスタに入れてみましょう。物理メモリを変更すると、レジスタ内の値は変更されません。

Javaメモリモデル(JMM)は古いもののようなメインメモリについては言及せず、進歩の保証もしていませんが(実際には非常に難しい)、 volatile/は、仕様の前に、レジスタ間の同期やスレッド間の同期が解除されます。

関連する問題