2

競合状態の例を書きたかっただけです:

MyParallelClass.java :

public class MyParallelClass implements java.lang.Runnable {
    public int counter = 0;

    @Override
    public void run() {
        if (test.globalVar > 0) {
            for (int i = 0; i < 1000000; i++) {
                counter++;
            }
            test.globalVar--;
        }
    }
}   

test.java :

public class test {
    public static int globalVar;

    public static void main(String[] args) {
        globalVar = 1;

        MyParallelClass a = new MyParallelClass();
        MyParallelClass b = new MyParallelClass();

        new Thread(a).start(); // Thread A
        new Thread(b).start(); // Thread B

        System.out.println(globalVar);
    }
}   

私が起こると思ったこと:

0スレッドBが開始する前にスレッドAが完全に実行された場合、これはどちらかを出力できると思いました。

変数は、次のtest.globalVarように操作することもできます。

Thread A                     -  Thread B  
checks if (globalVar > 0)
      looping ...               checks if (globalVar > 0)
      looping ...               execute all four bytecode commands of "test.globalVar--;"
      execute test.globalVar--;

の値はtest.globalVarになります-1

したがって、if ステートメントのいずれか、または両方が実行されます。

実際に起こったこと:

main メソッドの出力としてとを取得0しました。andではなくand1を取得するのはなぜですか?010-1

4

4 に答える 4

3

globalVarあなたは2回減少しています。最後に可能な値globalVarは次のとおりです。

  • -1- すべてがうまくいき、出力される前に両方のスレッドが値を正しくデクリメントした場合

  • 0:

    • 1 つのスレッドだけが変数をデクリメントでき、2 番目のスレッドがそれを出力する前に終了できなかった場合

    • globalVarが同時にデクリメントされた場合

  • 1:

    • 両方のスレッドが完了する前に実行できた場合System.out.println()(かなり可能性が高い)。はglobalVar確かに変更されましたが、すでに印刷された後です

    • 可視性の問題により、スレッドには、別のスレッドによって変更された値ではなく、main元の値が表示されます。globalVar他のスレッドによって行われた変更をすぐに (または常に) 確認するには、何らかの同期またはvolatileキーワードが必要です。

于 2012-07-30T19:37:54.840 に答える
1

System.out.println(globalVar);

スレッドが完了するのを待ちません。スレッドはその時点で完了している場合と完了していない場合があります。したがって、値は01、または-1両方のスレッドが完了したか、一方が完了したか、または両方が完了しなかったかに応じて異なります。

より良いテストを行うには、
-Thread.sleep()スレッドで使用して、遅延があることを確認します
- 異なるスレッドで異なる遅延を使用して、競合状態をより適切に視覚化します。
- 変数の値をスレッドにも出力したい場合があります。このようにして、3 つのスレッド (A、B、およびメイン スレッド) が競合し、視覚化が向上します。

于 2012-07-30T19:39:15.793 に答える
0

良い質問。もっとテストを実行する必要があると思います。:-)

Runnable クラスのループをランダムなミリ秒数 (500 ~ 1000) でスリープするように変更してみてください。ちょうど 10 回ループします。予想される競合状態が得られないかどうかを確認してください。

私は、ほとんどのコンピュータがあまりにも速すぎると思います。単純なループでは、スレッドの切り替えを引き起こすのに十分な作業を行っていない可能性があります。

私はいつもこのようなバグに遭遇するので、この種の質問が大好きです。

于 2012-07-30T19:37:15.600 に答える
0

いずれかのスレッドが値をデクリメントする前に値が出力された場合、1 を取得できます。

于 2012-07-30T19:39:41.203 に答える