1

below code listings、ステートメント1とステートメント2のスレッドは安全ですか?彼らはを使用していVolatileIntWrapperます。

スレッドセーフでない場合、どのステートメントを同期ブロックでラップする必要がありますか?

public class Demo {

    public static void main(String[] args) {

        VolatileIntWrapper volatileIntWrapper = new VolatileIntWrapper() ;

        for(int i = 1 ; i <= 5 ; ++i){
            new ModifyWrapperIntValue(volatileIntWrapper).start() ; 
        }
    }
}

class VolatileIntWrapper{
    public volatile int value = 0 ;
}

class ModifyWrapperIntValue extends Thread{

    private VolatileIntWrapper wrapper ;
    private int counter = 0 ;

    public ModifyWrapperIntValue(VolatileIntWrapper viw) {
        this.wrapper = viw ;
    }

    @Override
    public void run() {

        //randomly increments or decrements VolatileIntWrapper primitive int value

        //we can use below statement also, if value in VolatileIntWrapper is private
        // wrapper.getValue() instead of wrapper.value
        //but, as per my understanding, it will add more complexity to logic(might be requires additional synchronized statements),
        //so, for simplicity, we declared it public


        //Statement 1
        while(wrapper.value > -1500 && wrapper.value < 1500){
            ++counter ;
            int randomValue = (int) (Math.random() * 2) ;

            //Statement 2
            wrapper.value += (randomValue == 0) ?   1       :       -1 ;
        }

        System.out.println("Executed " + counter + " times...");
    }
}
4

4 に答える 4

4

このvolatileキーワードは、フィールドの読み取りと書き込みの両方にメモリ バリアを提供します。つまり、複数のスレッドがフィールドにアクセスし、最新の値を読み取ることが保証され、それらの書き込みが他のスレッドによって認識されることが保証されます。

特に複数の読み取りステートメントと書き込みステートメントがある場合は、操作の順序に関する保証が提供されvolatileません。volatile intコードでは、ループ内のいくつかの場所にアクセスしています。

    while(wrapper.value > -1500 && wrapper.value < 1500){
        ...
        wrapper.value += (randomValue == 0) ?   1       :       -1 ;
    }

ここでの操作の順序は保証されません。スレッド A が をテストした直後に、スレッド Aが をテストする前にvalue > -1500、別のスレッドがそれを変更する可能性があります。または、スレッド A が両方のテストを実行し、次にスレッド B が両方のテストを実行し、スレッド A が値を割り当て、スレッド B が値を割り当てます。これがマルチスレッドの競合状態の性質です。value < 1500

whileループは、同期しない限りバグがあると思われるコードのセクションです。次のようなことを行う必要があります。そのセクションを同期すると、synchronizedキーワードはメモリバリア自体を提供するため、volatileキーワードは不要です。

   synchronized (wrapper) {
       while (...) {
         ...
       }
   }
于 2012-07-13T05:56:53.123 に答える
2

volatile フィールドは 1 回だけ使用しても安全です。(読み取りと書き込みは 2 回としてカウントされます)

フィールドを合計 4 回使用しているため、競合状態の場所が 3 つあります。

この例の問題点は、シングル スレッドで実行する方が高速で単純であるため、マルチスレッドで実行すると不自然で非効率的に見えることです。

于 2012-07-13T05:57:07.413 に答える
0

質問には次の解釈が必要です。

使用しているスレッドは安全であり、意図したとおりにプリミティブ値を読み取っています。

プリミティブ フィールドで同期ブロックを使用する特定の用語がありますが、次のことを行う必要があります。

  • フィールドのゲッターとセッターを使用します。
  • アクセサーと出来上がりの両方に同期を入れます。
于 2012-07-13T06:05:33.863 に答える
0

Java In Concurrencty揮発性変数を使用するには、次の基準を満たす必要があると述べています。

1.  Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;

2.  The variable does not participate in invariants with other state variables; and

3.  Locking is not required for any other reason while the variable is being accessed.
于 2012-07-13T10:36:18.853 に答える