2016-10-06 16 views
-1

は私の次のコードです:スレッドが正しく動作しない理由ここで

class Test { 
private int x = 0; 

public void incX() { 
    synchronized(this) { 
     ++x;       
    } 
    System.out.println("x is: "+x+"  "+Thread.currentThread().getName()); 
} 

public static void main(String[] args) { 
    Test test = new Test();    
    Thread t1 = new Thread(() -> { 
     test.incX();      
    }); 
    Thread t2 = new Thread(() -> { 
     test.incX();     
    }); 
    t1.start(); 
    t2.start(); 

    System.out.println("Done"); 
} 
} 

ここに私の出力です:そして、ここで

x is: 2  Thread-1 
x is: 1  Thread-0 

スレッドt2出力2が、t1も出力すべき2、右のスレッド? xが2のときと同様に、t1のスレッドに表示されるはずです。だからなぜt1スレッドが1ですか?

スレッドt2が2を出力し、スレッドt1が1を出力するのはどうでしょうか?スレッドt2はすでに2を出力しているので、xの値は2になります。したがって、スレッドt1はどのようにして1を出力できますか?私は誤解していますか?

+2

出力します。 – duffymo

+0

@duffymo:私が誤解していることを教えていただけますか? –

+0

他はより良い仕事をしています。コードがあなたの期待に合っていないときは、あなたの前提を確認するのが最善であると言うことを除いて、私が追加するものはありません。 – duffymo

答えて

3

まず、コードが正しく同期されていません。あなたの表現

"x is: "+x+"  "+Thread.currentThread().getName() 

は、データレースで、つまり、同期せずに共有変数xの値を読み取ります。しかし、先に​​ブロックで観測された値を少なくとも見ることになります。

ここで、プログラムの可能な出力を考えてみましょう。スレッドはステップごとに進行し、すべてのスレッドによるステップがインターリーブされます。次のシーケンスを考えてみましょう:

  1. Thread-0

    は、​​ブロックに入り、x == 0を読み込み1にそれを更新し、ブロックを残します。後続の文字列式は、この値1を読み取ります。
  2. Thread-1ブロックには、x == 1が読み込まれ、2に更新され、ブロックが残ります。後続の文字列式は、この値2を読み取ります。
  3. Thread-1は​​メソッドprintlnに入り、結果は2です。
  4. Thread-0は​​方法printlnに入り、その結果あなたはおそらく誤解されている1.
3

あなたの全体のSystem.out.println行は、非常に遠く離れています。
たとえば、文字列の作成とSystem.out.printlnの呼び出しの間に、多くのことが起こる可能性があります。

のは、同等のコードブロックを考えてみましょう:

public void incX() { 
    synchronized(this) { 
     ++x;       
    } 
    String implicit = "x is: " + x + "  " + Thread.currentThread().getName(); 
    // <-- "Point X" 
    System.out.println(implicit); 
} 

は今のシナリオは次のように行くことができます:

  • スレッド1が開始され、それが「ポイントX」に達するまでの文字列を構築した、に行きますその読み取り:

    xは:1つのスレッド0

  • スレッド2が開始され、それが「ポイントX」に達するまで読み込み、文字列を構築した上で行く:

    xは:2スレッド1

  • スレッド2は、全体的な出力を行う、System.out.printlnを呼び出しをこれまで:

    xがある:2スレッド1スレッド1がSystem.out.println、全体的な出力を作る呼び出す

  • xがある:2スレッド1 xがある:1つのスレッド0

​​ブロック内の別の変数にxの値をコピーする動作が会うせるのに十分であるべきであるあなたの期待:

public void incX() { 
    int val; 
    synchronized(this) { 
     val = ++x;       
    } 
    System.out.println("x is: " + val + "  " + Thread.currentThread().getName()); 
} 
関連する問題