6

私は得てjava.lang.IllegalMonitorStateExceptionいた。この質問を参照して、問題を解決しました。最初の答えは

To be able to call notify() you need to synchronize on the same object.

synchronized (someObject) {
    someObject.wait();
}

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}  

私の質問は、同じオブジェクト広告で同期する必要があるのはなぜですか?

私たちが言うとき、私の理解が行く限り

synchronized (someObject) {
    someObject.wait();
}

オブジェクト someObject をロックしてから、wait() を呼び出します。別のスレッドが同じオブジェクトをロックして、そのオブジェクトで notify() を呼び出すにはどうすればよいでしょうか? 私は何が欠けていますか?

4

4 に答える 4

8

なぜnotifyロックも必要なのですか?

次のシナリオを想像してください。

synchronized(x){
        while(x.count < 4) {
          x.wait();
          //...
        }
}

notify周囲にロックのない別の場所を想像してみてください:

//...
println(x.count); // print 3
x.count++;
if(count == 4) 
  x.notify()
//...

一見すると、サウンド全体が常に期待どおりに機能します。
ただし、次の競合状態を想像してください。

//Thread1 enters here
synchronized(x){
     while(x.count < 4) {
         //condition is judged true and thread1 is about to wait 
         //..but..ohh!! Thread2 is prioritized just now !
         //Thread2, acting on notify block side, notices that with its current count incrementation, 
         //count increases to 4 and therefore a notify is sent.... 
         //but...but x is expected to wait now !!! for nothing maybe indefinitely !
       x.wait();
       //maybe block here indefinitely waiting for a notify that already occurred!
     }
}

これを側に伝える方法があればnotify

スレッド 1: 「うーん..notifyかわいいけど、私は自分の状態 ( x.count < 4) を true に評価し始めたばかりなので、お願いします... 期待どおりの通知を今すぐ送信して愚かにしないでください (ステータスをそうでなければ、すでに過ぎ去ったものを待つのはばかげているでしょう。」

スレッド 2: 「わかりました...一貫性を保つためにロジックをロックします。待機呼び出しが共有ロックを解放した後に通知を送信します。したがって、この通知を受け取り、待機を終了することができます。状態 ;)"

notifyしたがって、この状況を回避し、関係を常に一貫させるために、待機によって保持されている同じオブジェクトの側に常にロックを配置します。

=> a に至るnotify論理と a に至る論理は、wait決して重複してはなりません。

于 2013-08-07T08:52:57.903 に答える
5

Object#wait()の javadoc に従って

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

待機/通知を使用するには、スレッドにロックが必要です。そうでない場合、 IllegalMonitorStateExceptionがスローされます

例外: IllegalMonitorStateException - 現在のスレッドがオブジェクトのモニターの所有者でない場合。

どうして

したがって、 wait()現在のスレッドにロックを解放させます

notify()ロックを取得しようとする他の待機中のスレッドにシグナルを送信します。

いずれかを実行するには、現在のスレッドにロックが必要です。そして、それは理にかなっています!

編集

  • wait() を呼び出すスレッドがロックを保持しなければならない理由は、今やかなり明白です。

  • しかし、notify() を呼び出すスレッドがロックを保持しなければならないのはなぜでしょうか? まあ、一つには、それを証明するためにauthenticity。そうしないfalse notificationsと、スレッドが起動し続け、waitingスレッドが中断され続ける可能性があります。ありがたいことに、そうではありません。

于 2013-08-07T05:28:16.543 に答える
1

通常、待機/通知は、他のスレッドがタスクを完了するのを待機するか、特定の条件が満たされるまで待機するために使用されます。

objectAというオブジェクトと、thread1 および thread2という 2 つのスレッドがあるとします。
thread1にはスレッドセーフなタスクがあるため、同期ブロック を使用して objectA のモニターを取得します。

       synchronized (objectA) {
          //here thread1  owns objectA's monitor
       }  

Java では、wait() を呼び出すことは、他のスレッドがこのモニターを取得してそのタスクを実行できるようにモニターを解放することを意味し、現在のスレッドはobjectA のモニターの待機状態と呼ばれる状態になります。

     synchronized(objectA){
        //here thread1 owns objectA's monitor.
        objectA.wait();
        //here thred1 releases monitor of objectA's monitor and goes into waiting state and waits to get objectA's monitor once again to complete its task.
     }

これで、thread2 は objectA のモニターを所有し、そのタスクを実行できます。

    synchronized(objectA){
        //here thread2 owns objectA's monitor.
        //some task;
     }

タスクが完了すると、待機状態にある他のスレッドに、所有するオブジェクトのモニターが解放されたことを通知します。notify()を呼び出すには、スレッドもオブジェクト monitor の所有者である必要があることに注意してください

       synchronized(objectA){
        //here thread2 owns objectA's monitor.
        //some task;
        objectA.notify();
       //it signals some other thread that it can wake up from wait,so that other waiting threads can owns objectA's monitor
     }

ここで、 objectAで wait() を呼び出し、他のオブジェクト (objectB としましょう) で notify() を呼び出しても、thread1 は使用ませ

1 つのオブジェクトで notify() を呼び出そうとする 2 つのスレッドが互いに足を踏み入れないことが保証されているため (競合状態を回避するため)、notify()Why obtain monitor to call notify()
を 呼び出すように更新します。通知する前にロックを取得する必要がある理由

于 2013-08-07T06:08:51.430 に答える