0

待機/通知メソッドを使用する例に遭遇したとき、私は Kathy Sierra の本のスレッド化の章を見ていました:

 class ThreadA {
 public static void main(String [] args) {
 ThreadB b = new ThreadB();
 b.start();

 synchronized(b) {
 try {
    System.out.println("Waiting for b to complete...");
    b.wait();
     } catch (InterruptedException e) {}
 System.out.println("Total is: " + b.total);
 }
}
}

class ThreadB extends Thread { 
 int total;
 public void run() {
  synchronized(this) {
   for(int i=0;i<100;i++) {
   total += i;
   }
  notify();
 }
}
}

コードを実行すると、常に同じ出力が生成されます。

b が完了するのを待っています... 合計: 4950

以下を追加して、ThreadB の run() の同期ブロックを変更しました。

System.out.println("ThreadB is executed"); 

問題は、なぜ私は取得し続けるのですか

「b が完了するのを待っています...」

「スレッド B が実行されます」

? スレッド b がメインスレッドより先に実行される可能性はありませんか?

4

2 に答える 2

5

スレッド b がメインスレッドより先に実行される可能性はありませんか?

はい、そのような可能性はありますが、このコードのような狭いレースではほとんどありません。

コードはb.start()、b のモニター (同期ブロック) を取得する前に呼び出します。そのウィンドウ中にメイン スレッドがプリエンプトされる可能性があり、そのスレッド B が最初に実行され、そのモニターを取得します。

そのような状況では、メイン スレッドがスレッド B からの呼び出しwait()を逃したため、このプログラムはハングします。notify()

于 2013-04-12T19:48:36.020 に答える
5

スレッド b がメインスレッドより先に実行される可能性はありませんか?

そのとおり。

通常wait、この種の問題を防ぐための述語が伴います。

たとえば、ThreadB は、終了したことを示す変数を持つことができます。あなたの場合、合計が0でないかどうかを確認できます。

synchronized (b) {
    try {
        System.out.println("Waiting for b to complete...");
        while (b.total == 0) {
            b.wait();
        }
    } catch (InterruptedException e) {
    }
    System.out.println("Total is: " + b.total);
}

これにより、ThreadB での書き込みに関して、total の読み取りで発生前の関係が作成されます。

于 2013-04-12T19:40:27.310 に答える