1

両方のスレッドで変数を共有したいのですが、実行時に 1 と 2 ではなく 2 が 2 回出力されることがあります。

public class man implements Runnable{

    int value = 0;

    public static void main(String[] args){
        Runnable job = new man();
        Thread work1 = new Thread(job);
        work1.setName("Thread1");
        Thread work2 = new Thread(job);
        work2.setName("Thread2");

        work1.start();
        work2.start();
    }


    public void run(){
        synchronized(this){
            value = value + 1;
        }
        System.out.println("VALUE = " + value +", Running " + Thread.currentThread().getName());
    }



}

出力は時々次のとおりです。

VALUE = 2, Running Thread2
VALUE = 2, Running Thread1

その他の時間は次のとおりです。

VALUE = 1, Running Thread2
VALUE = 2, Running Thread1

なぜこうなった?私は HeadFirst の本で Java を学んでいますが、この質問が出てきました。

4

2 に答える 2

3

変数へのアクセスを同期する必要があります。

何が起こっているかというと、両方のスレッドが変数の値をインクリメントした後、両方のスレッドが変数の値を読み取っているということです。言い換えると:

  1. スレッド 1: syncronized(this) => スレッド 2 は自身の syncronized(this) に入ることができません
  2. スレッド 1: 値 = 値 + 1 ; => 1 と言う
  3. スレッド 1: 同期化されたブロックを終了します => スレッド 2 は、独自の同期化された (this) に入ることができます
  4. スレッド 2: syncronized(this) => スレッド 1 は自身の syncronized(this) に入ることができません
  5. スレッド 2: 値 = 値 + 1 ; => 2
  6. スレッド 2: 値、つまり 2 を出力します
  7. スレッド 1: 値、つまり 2 を出力します

解決策は、ブロックSystem.out.println("VALUE = " + value +", ...);内に移動することです。synchronizedこれにより、上記のシーケンスが強制的に次のように並べ替えられます。

  1. スレッド 1: syncronized(this) => スレッド 2 は自身の syncronized(this) に入ることができません
  2. スレッド 1: 値 = 値 + 1 ; => 1 と言う
  3. スレッド 1: 値、つまり 1 を出力します
  4. スレッド 1: 同期化されたブロックを終了します => スレッド 2 は、独自の同期化された (this) に入ることができます
  5. スレッド 2: syncronized(this) => スレッド 1 は自身の syncronized(this) に入ることができません
  6. スレッド 2: 値 = 値 + 1 ; => 2
  7. スレッド 2: 値、つまり 2 を出力します
于 2013-09-01T00:00:06.620 に答える
3

呼び出し内でアクセスを同期していないSystem.out.printlnため、「最初のスレッド」が出力される前に「2 番目の」スレッドがインクリメントされることがあります。

于 2013-08-31T23:50:42.713 に答える