2016-10-04 20 views
1

私は2つのスレッドを開始しています.1,3,5、...、2つのスレッドは、2つのT2プリント2,4,6 ....です。スレッドの実行が予測不可能

public class T1T2Print { 
    public static void main(String[] args) { 
     Counter c = new Counter(); 
     c.count = 1; 
     printThread t1 = new printThread(c); 
     Thread T1 = new Thread(t1); 
     T1.setName("T1"); 
     printThread t2 = new printThread(c); 
     Thread T2 = new Thread(t2); 
     T2.setName("T2"); 
     T2.start(); 
     T1.start(); 
    } 

} 

class printThread implements Runnable { 
    public Counter count; 
    public int reminder; 



public printThread(Counter count) { 
    this.count = count; 
} 

public void run() { 
    for (int i = 1; i <= 5; i++) { 
     synchronized (count) { 
      String name = Thread.currentThread().getName(); 

      if (count.count % 2 != 0 && !name.equals("T1")) { 
       try { 
        count.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } else { 
       System.out.println(name + " :: " + count.count); 
       count.count++; 
       count.notify(); 
      } 

      if (count.count % 2 == 0 && !name.equals("T2")) { 
       try { 
        count.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } else { 
       System.out.println(name + " :: " + count.count); 
       count.count++; 
       count.notify(); 
      } 

     } 
    } 
} 
} 

出力は以下の通りです:

T1 :: 1 
T2 :: 2 
T1 :: 3 
T2 :: 4 
T1 :: 5 
T2 :: 6 
T1 :: 7 
T2 :: 8 
T1 :: 9 
T2 :: 10 

が、私は以下のように出力が変化

T1.start(); 
T2.start(); 

にスレッドを開始する順序を変更、なぜこの動作

T1 :: 1 
T2 :: 2 
T2 :: 3 
T2 :: 4 
T2 :: 5 
T2 :: 6 
T2 :: 7 
T2 :: 8 
T2 :: 9 
T2 :: 10 
T2 :: 11 
T1 :: 12 
T1 :: 13 
T1 :: 14 
T1 :: 15 
T1 :: 16 
T1 :: 17 
T1 :: 18 
T1 :: 19 
+0

私の推測では、あなたがここで詳細に明らかでない何か間違ったことをやっているです:

あなたif文は次のようなものに固定することができます。 'wait()'を呼び出す場合は、それを行う必要があります。私はそれが待っていることを示すためにprintステートメントを追加します。 –

答えて

1

ifにはいくつかの問題があります。反復ごとに、カウンタを2回インクリメントすることができます。

たとえば、カウンタが2の場合はT2スレッドを作成するには、値を2回増分します。 count.count % 2 != 0はfalseであるため、elseが実行され、カウンタがインクリメントされます。カウンタは3になり、count.count % 2 == 0はfalseなので、2番目のelseも実行され、カウンタが増加し、予期せぬ出力が得られるため、2番目のifも偽です。

public void run() { 
    for (int i = 1; i <= 5; i++) { 
     synchronized (count) { 
      String name = Thread.currentThread().getName(); 

      if (name.equals("T1")) { 
       while (count.count % 2 == 0) { 
        try { 
         count.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println(name + " :: " + count.count); 
       count.count++; 
       count.notify(); 
      } else if (name.equals("T2")) { 
       while (count.count % 2 != 0) { 
        try { 
         count.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println(name + " :: " + count.count); 
       count.count++; 
       count.notify(); 
      } 
     } 
    } 
} 
+0

だから、whileはスピンロックのようなものです。 – user2478236

+0

'wait'の後に再び条件を確認することは良い習慣です。それは 'while'を' if'でも置き換えて動作します。 –

2

私たちに追加しますの前にが呼び出されます。

そして、最初のケースログ:

T2 :: waits 
T1 :: 1 
T1 :: waits 
T2 :: 2 
T2 :: waits 
T1 :: 3 
T1 :: waits 
T2 :: 4 
T2 :: waits 
T1 :: 5 
T1 :: waits 
T2 :: 6 
T2 :: waits 
T1 :: 7 
T1 :: waits 
T2 :: 8 
T2 :: waits 
T1 :: 9 
T1 :: waits 
T2 :: 10 

第二ケースログ:あなたが第二の場合には見ることができるようにスレッドが寝ていない

T1 :: 1 
T1 :: waits 
T2 :: 2 
T2 :: 3 
T1 :: 4 
T1 :: 5 
T1 :: 6 
T1 :: 7 
T1 :: 8 
T1 :: 9 
T1 :: 10 
T1 :: 11 
T2 :: 12 
T2 :: 13 
T2 :: 14 
T2 :: 15 
T2 :: 16 
T2 :: 17 
T2 :: 18 

。どうして? 2番目のケースでは、各スレッドがカウンタを2回(1回目はifに、1回目は2回目にif)に増やす(同期方法で行う)ためです。 (私はあなたがこのロジックを望まないと仮定することができ、これはあなたが作ったエラーです)。ケースの違いは?最初のケースでは、T2が先に開始され、最初に通知された後で待機し、それが起動して2番目のifに移動します。つまり、1回の繰り返しにつき1回だけカウンタを増加(および印刷)します。それが理由です。

関連する問題