3

The following code is in the SCJP6 book

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();
         }
     }
 }

Won't the previous code cause a deadlock as both thread a and b have a lock on b (in the respective synchronized blocks)?

I am missing something, but not quite sure what it is.

4

2 に答える 2

6

最も可能性の高い実行は次のとおりです。

  • メソッドが実行されるまでにわずかな遅延がb.start()ありますrun
  • したがって、メインスレッドはなんとかロックを取得し、ブロックbに入りますsynchronized
  • 次に待機しますbロックを解放します
  • 実行がrun開始されると、モニターが使用可能になる (またはすぐに使用可能になる) ため、synchronizedブロックに入ることができます。
  • b完了すると、待機を停止できることが通知されます
  • メインスレッドが完了します。

ただし、スレッドのスケジューリングによっては、 が最初に実行されることは不可能ではありませんrun。その場合、メイン スレッドは で永遠に待機する可能性がありますb.wait()。たとえば、 のThread.sleep(100)直後に小さな を挿入してその状況を改善するb.start()場合は、その動作を観察する必要があります。

結論: これは、活性の問題が発生する可能性のある悪臭を放つコードです (ロックが使用可能であるため、それ自体はデッドロックではありません)。

于 2013-03-29T11:05:16.540 に答える
4

場合によります。

待機メソッドのドキュメントから-

別のスレッドがこのオブジェクトの notify() メソッドまたは notifyAll() メソッドを呼び出すまで、現在のスレッドを待機させます。つまり、このメソッドは、wait(0) の呼び出しを実行するかのように動作します。

現在のスレッドは、このオブジェクトのモニターを所有している必要があります。スレッドは、このモニターの所有権を解放し、別のスレッドが、このオブジェクトのモニターで待機しているスレッドに、notify メソッドまたは notifyAll メソッドの呼び出しによってウェイクアップを通知するまで待機します。スレッドは、モニターの所有権を再度取得できるまで待機し、実行を再開します。

したがって、2 つのシナリオを考慮すると、

  • 最初にオブジェクトThreadAのロックを取得するbと、待機し、結果としてロックが解放されThreadB、作業が続行されます。
  • 最初にロックを取得するとThreadB、作業が続行され、ロックが解除されてThreadAから開始されます。次に、ThreadAオブジェクト lock を待機しbます。これにより、永久に待機する可能性があります。
于 2013-03-29T11:05:09.410 に答える