6

私はスレッドの観点からのみ尋ねています...おそらく何度も答えられますが、これを理解するのを手伝ってください。

ここの投稿を参照して、 Volatile Vs Static in Java

静的変数の値を要求することも、すべてのスレッドに対して 1 つの値になります。次の例を見つけました:

public class VolatileExample {  
public static void main(String args[]) {  
    new ExampleThread("Thread 1 ").start();  
    new ExampleThread("Thread 2 ").start();  
}  

}  
class ExampleThread extends Thread {  
private static volatile int testValue = 1;  
public ExampleThread(String str){  
    super(str);  
}  
public void run() {  
    for (int i = 0; i < 3; i++) {  
        try {  
            System.out.println(getName() + " : "+i);  
            if (getName().compareTo("Thread 1 ") == 0)  
            {  
                testValue++;  
                System.out.println( "Test Value T1: " + testValue);  
            }  
            if (getName().compareTo("Thread 2 ") == 0)  
            {  
                System.out.println( "Test Value T2: " + testValue);  
            }                 
            Thread.sleep(1000);  
        } catch (InterruptedException exception) {  
            exception.printStackTrace();  
          }  
       }  
       }  
       }

出力:

Thread 1 : 0
Test Value T1: 2
Thread 2 : 0
Test Value T2: 2
Thread 1 : 1
Test Value T1: 3
Thread 2 : 1
Test Value T2: 3
Thread 1 : 2
Test Value T1: 4
Thread 2 : 2
Test Value T2: 4

testValue から static を削除すると、次の結果が得られます。

Thread 1 : 0
Test Value T1: 2
Thread 2 : 0
Test Value T2: 1
Thread 1 : 1
Test Value T1: 3
Thread 2 : 1
Test Value T2: 1
Thread 1 : 2
Test Value T1: 4
Thread 2 : 2
Test Value T2: 1

スレッド 2 が更新された値を読み取らないのはなぜですか? static にする必要がある場合、volatile の使用は何ですか?

その変数が static と宣言されていない volatile の良い例へのリンクを誰かが与えることができますか?

ありがとう

4

4 に答える 4

4

問題は、++がアトミックではないことです。コードはAtomicInteger代わりに使用する必要があります。変数を使用staticすると、両方のスレッドが同じ値を更新しようとし、++は実際にはget、+ 1、およびstoreの3つの操作になります。これは、両方のスレッド間に競合状態があり、それらが互いに上書きしていることを意味します。

スレッド2が更新された値を読み取らないのはなぜですか?静的にする必要がある場合、揮発性の使用はどうなりますか?

staticさまざまなことをvolatileします。 staticオブジェクトインスタンスではなく、クラスに関連付けられたフィールドを作成します。 volatileフィールドの読み取りまたは書き込みを強制的にメモリバリアを通過させます。これにより、複数のスレッドが共通のフィールドを読み取って更新できるようになりますが、複数の操作から保護されるわけではありません。変数を静的にしない場合はvolatile、各スレッドがフィールドの独自のインスタンスで動作するため、必要ありません。

を使用する必要がありますAtomicInteger。これはをラップしますvolatile intが、インクリメント操作の特別な処理も提供します。

private static AtomicInteger testValue = new AtomicInteger(1);
...
testValue.incrementAndGet();

誰かがその変数が静的であると宣言されていない揮発性の良い例へのリンクを与えることができますか?

volatile複数のスレッドで共有されている場合は、非静的フィールドにが必要になります。たとえば、上に移動しtestValueてから、VolatileExampleクラスの同じインスタンスVolatileExampleを両方のスレッドに渡して、アクセスできるようにしたとしますtestValue

于 2013-02-25T14:19:18.927 に答える
4

を使用volatileすると、すべてのスレッドが同時に同じ値を参照できるようになります。基本的に、この変数は決してキャッシュされるべきではないと言っています。

キャッシュ戦略は cpu から cpu へ、また JRE から JRE へと変化するため、コードで示すのは困難です。

volatileJRE に伝えたいことは、この値をキャッシュする誘惑に駆られたことがあれば、そうすることでコードの実行速度を少し速くできると考えている場合です... 私はプログラミングについてあなたよりもはるかによく知っています。あなたがそうすると、私のコードが壊れてしまうことは間違いありません。.

于 2013-02-25T14:17:19.520 に答える
0

この場合、 tou がstatic修飾子を削除したときに変数が変更されました。これは、それぞれExampleThreadが独自のを持っているtestValueためです。そのため、格納値はスレッド インスタンスごとに異なります。

static修飾子の意味:

場合によっては、すべてのオブジェクトに共通の変数が必要になることがあります。これは static 修飾子で実現されます。宣言に static 修飾子があるフィールドは、静的フィールドまたはクラス変数と呼ばれます。オブジェクトではなく、クラスに関連付けられています。クラスのすべてのインスタンスは、メモリ内の 1 つの固定位置にあるクラス変数を共有します。どのオブジェクトでもクラス変数の値を変更できます...

リファレンス:インスタンスとクラス メンバーについて

について、次のように変数をクラスvolatileに移動して、別の種類のテストを試す場合:testValueVolatileExample

 public class VolatileExample {
    private volatile int testValue = 1;
 ...
 }

次に、を削除しtestVariableExampleThreadコードを実行します。その出力は最初のもののようになるはずです。

volatile修飾子の意味:

volatile 変数を使用すると、メモリの整合性エラーのリスクが軽減されます。これは、volatile 変数への書き込みによって、同じ変数の後続の読み取りとの先行発生関係が確立されるためです。これは、揮発性変数への変更が常に他のスレッドに見えることを意味します

参考:アトミックアクセス

于 2013-02-25T17:21:22.453 に答える
0

あなたの最後の質問「その変数が静的に宣言されていない揮発性の良い例へのリンクを誰かが与えることができますか?」この概念を明確に理解できるようになり、例がありました。

    public class VolatileExample {

   // public static volatile int testValue = 1;
    public  int nonstatic=8;
    public static void main(String args[]) {
        VolatileExample volatileExample=new VolatileExample();
        new ExampleThread("Thread 1 ",volatileExample).start();
        new ExampleThread("Thread 2 ",volatileExample).start();
    }

}
class ExampleThread extends Thread {
VolatileExample volatileExample;
    public ExampleThread(String str,VolatileExample volatileExample){
        super(str);
        this.volatileExample=volatileExample;
    }
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                if (getName().compareTo("Thread 1 ") == 0)
                {
                   volatileExample.nonstatic++;
                    System.out.println( "Test Value T1: " + volatileExample.nonstatic);


                }
                if (getName().compareTo("Thread 2 ") == 0)
                {
                    System.out.println( "Test Value T2: " + volatileExample.nonstatic);
                    Thread.sleep(1);
                }
               // Thread.sleep(1000);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        }
    }
}

public int nonstatic=8; を作成して変更を確認してください。揮発性

以下は、揮発性にされたときの出力です。

テスト値 T1: 9 テスト値 T1: 10 テスト値 T1: 11 テスト値 T2: 11 テスト値 T2: 11 テスト値 T2: 11

プロセスは終了コード 0 で終了しました

テスト値 T1: 9 テスト値 T2: 9 テスト値 T1: 10 テスト値 T1: 11 テスト値 T2: 11 テスト値 T2: 11

プロセスは終了コード 0 で終了しました

観察:Volatile keyWord はスレッドをメイン メモリに直接書き込むようにするため、スレッドはより速くループに戻ります。したがって、Volatile にすると、スレッド 1 はより速くタスクを完了し、スレッド 2 がターンを開始する前にループに戻ります。

反対に、スレッドを不揮発性にすることで、スレッドはその locl キャッシュを更新し、それをメイン メモリに報告するようになります...そのため、このサイクル中に、スレッド 2 がレースに参加しました。

PLz注意、これを示すために、ExampleThreadではなくVolatileExampleクラスに「非静的」変数があります。

あなたの他の質問は: スレッド 2 が更新された値を読み取らないのはなぜですか? static にする必要がある場合、volatile の使用は何ですか?

テスト値を非静的にすると、クラス ExampleThread の 2 つの異なるオブジェクト Thread1 と Thread2 だけが独自の変数 testvalue で動作するようになります.... volatile は実際には問題になりません..

于 2015-11-10T04:56:59.163 に答える