4

ここには、3 つの単純なクラスがあります。

クラス 1:

public class ThreadSyncMain {

public static int count = 0; // volatile is not use

public static void main(String[] args) {

    Thread thread1 = new Thread( new Thread1(),"Thread1" ); 
    Thread thread2 = new Thread( new Thread2(),"Thread2");

    thread1.start();
    thread2.start();

}

}

クラス 2:

public class Thread1 implements Runnable{
public void run() {

    System.out.println("Thread1 Count :: "+ThreadSyncMain.count);
    ThreadSyncMain.count++;
}

}

クラス 3:

public class Thread2 implements Runnable{
public void run() {

        System.out.println("Thread2 Count :: "+ThreadSyncMain.count);

}
}

出力は次のとおりです。

スレッド 1 カウント :: 0
スレッド 2 カウント :: 1

これは、thread1 が count の値を変更したことを意味します。「揮発性」キーワードを使用していないため、スレッド1の変更がスレッド2に影響するのはなぜですか。このシナリオでは「揮発性」キーワードは問題ではありませんか? 「揮発性」をテストするためにコードを変更するにはどうすればよいですか?

前もって感謝します。

更新部分:いくつかのヒットテストと試行テストを行った後、コードを更新しています。クラス1はそのまま。更新されたコードは次のとおりです。

クラス 2: 100 ミリ秒の遅延を追加しました。

public class Thread1 implements Runnable{
public void run() {

    System.out.println("Thread1 Count :: "+ThreadSyncMain.count);

    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    ThreadSyncMain.count++;
}

}

クラス 3: while ループを追加。内部では、カウントが継続的に監視されます。

public class Thread2 implements Runnable{
public void run() {

    while(true)
    {
        if(ThreadSyncMain.count == 1)
        { 
            System.out.println("Thread2 Count :: "+ThreadSyncMain.count);
        }
    }

}
}

この状況で、次の出力が得られました
。 1. class1 で「volatile」が使用されていない場合の出力

 Thread1 Count :: 0

2. class1 で「volatile」が使用されている場合、出力は次のようになります。

Thread1 Count :: 0
Thread2 Count :: 1
Thread2 Count :: 1
Thread2 Count :: 1
.
.
.

このシナリオで volatile が登場するのはなぜですか?

4

3 に答える 3

3

各スレッドに関連付けられたメモリビューがあります。これらのビューは、ロックを使用せずにスレッド間で一貫していることが保証されていません。そのため、上記で行ったように(なしでvolatile)変数を共有すると、スレッド間で表示されるため機能しますが、信頼性の低い結果が得られる可能性があります。volatileキーワードを使用することは、変数がスレッド間で一貫して読み取られることを意味します。

ここを参照してください。特に注意してください。

揮発性フィールドは、スレッド間で状態を通信するために使用される特別なフィールドです。揮発性の読み取りごとに、任意のスレッドによるその揮発性への最後の書き込みが表示されます。事実上、これらはプログラマーによって、キャッシュまたは並べ替えの結果として「古い」値を表示することは決して受け入れられないフィールドとして指定されます。

于 2012-11-14T10:11:02.243 に答える
3

Volatileスレッド 1 からの副作用がスレッド 2 に見えるようになることを保証volatileします。

の効果をテストするのvolatileは困難です。これは、ハードウェア アーキテクチャ、スレッド化の実装、コンパイラの最適化、スケジューラによる の正確なタイミングなどの低レベルの側面に依存するためです。

その場合、高い並行性を生成するマルチスレッド テストを作成し、マルチプロセッサの実装で実行するようにします。次に、 がある場合とない場合のコードの違いを観察するかもしれませんvolatile。テストの結果はまだ決定論的ではありません。

于 2012-11-14T10:15:34.667 に答える
1

クラス全体の変数であるため、コンパイラがカウンターをキャッシュしていない可能性があります。したがって、書き込みはメモリ内にあります。

揮発性および不揮発性の書き込み/読み取りをテストする場合..

public class VolatileExperiment
{
  private int counter ;
  private volatile int volatile_counter;
  public void Counter()
  {
     new Thread( new Runnable(){
     public void run()
     {
        ++counter;
        ++volatile_counter;
        //print
      }
    }).start();


   new Thread( new Runnable(){
     public void run()
     {
       ++counter;
       ++volatile_counter;
       //print
      }
    }).start();
    //print counter 
   //print volatile 
  }

}

volatile を使用すると、コンパイラがコードを最適化しないことが保証されるため、書き込みはスレッド メモリではなくメモリで行われます。したがって、volatile_counterupdated..が表示されるはずですcounterが、影響を受けない可能性があります

于 2012-11-14T10:14:45.933 に答える