wait()
メソッドとメソッドがクラスではなくクラスでnotify()
宣言されているのはなぜですか?Object
Thread
9 に答える
特定のオブジェクト (または具体的にはそのモニター) がこの機能を使用するのを待つためです。
これらの方法がどのように機能するかを誤解している可能性があると思います。それらは単純にスレッド粒度レベルにあるわけではありません。つまり、単に を呼び出して次の呼び出しによって起動されるというケースではありません。むしろ、常に特定のオブジェクトを呼び出し、そのオブジェクトの呼び出しによってのみ起動されます。wait()
notify()
wait()
notify
そうしないと同時実行プリミティブはスケーリングされないため、これは良いことです。プログラム内の任意の場所への呼び出しは、呼び出しでブロックしているスレッドを起動するため、並行コードをnotify()
台無しにする可能性があるため、グローバル名前空間を持つことと同じです。したがって、特定のオブジェクトでそれらを呼び出す理由。これは、wait-notify ペアが操作するためのコンテキストを提供するため、プライベート オブジェクトで を呼び出すと、クラスで待機メソッドを呼び出したスレッドのみを確実に起動できます。別のオブジェクトを待機している可能性のある一部の Spring スレッドは、この呼び出しによってウェイクアップされず、その逆も同様です。wait()
myBlockingObject.notify()
編集:または別の観点からそれに対処するには-あなたの質問から、待機中のスレッドへのハンドルを取得し、そのスレッドnotify()
を呼び出してそれを起こすと思ったと思います。このようにしない理由は、多くのハウスキーピングを自分で行わなければならないからです。待機するスレッドは、他のスレッドが参照できる場所に自分自身への参照を公開する必要があります。一貫性と可視性を確保するには、これを適切に同期する必要があります。スレッドを起動したい場合は、この参照を取得し、起動し、読み取り元から削除する必要があります。手動のスキャフォールディングがより多く含まれており、単に呼び出しを行う場合に比べて (特に並行環境では) うまくいかない可能性が高くなります。myObj.wait()
スリープスレッドで、次にmyObj.notify()
ウェイカースレッドで。
最も単純で明白な理由は、(スレッドだけでなく) 任意のオブジェクトがスレッドのモニターになる可能性があるためです。待機と通知はモニターで呼び出されます。実行中のスレッドはモニターでチェックします。そのため、待機メソッドと通知メソッドはスレッドではなくオブジェクトにあります
一度に 1 つのスレッドのみがオブジェクトのモニターを所有でき、このモニターはスレッドが待機または通知しているものであるためです。javadoc forObject.notify()
を読んObject.wait()
で、詳細に説明されている場合。
同期のメカニズムには、オブジェクトのモニターという概念が含まれます。wait() が呼び出されると、モニターが要求され、モニターが取得されるか、InterruptedException が発生するまで、以降の実行は中断されます。notify() が呼び出されると、モニターが解放されます。
wait() と notify() が Object クラスではなく Thread クラスに配置された場合のシナリオを考えてみましょう。コードのある時点でcurrentThread.wait()
が呼び出され、オブジェクトanObject
がアクセスされます。
//.........
currentThread.wait();
anObject.setValue(1);
//.........
currentThread.wait() が呼び出されると、監視currentThread
が要求され、監視が取得されるか、InterruptedException が発生するまで、それ以上の実行は行われません。待機状態のときに、 に存在する別foo()
のオブジェクトのメソッドが別のスレッドから呼び出されると、呼び出されたメソッドが にアクセスしなくてもスタックします。スレッド自体ではなく で最初の wait() メソッドが呼び出された場合、同じスレッド内に存在するオブジェクトで ( にアクセスしない) 他のメソッド呼び出しが停止することはありませんでした。anotherObject
currentThread
foo()
anObject
anObject
anObject
したがって、Object クラス (またはそのサブクラス) で wait() メソッドと notify() メソッドを呼び出すと、同時実行性が向上します。そのため、これらのメソッドは Thread クラスではなく Object クラスにあります。
他のいくつかの回答では「モニター」という言葉が使用されていますが、その意味を説明しているものはありません。
「モニター」という名前は 1970 年代に造られたもので、固有のロックと関連付けられた待機/通知メカニズムを持つオブジェクトを指していました。https://en.wikipedia.org/wiki/Monitor_%28synchronization%29
20 年後、デスクトップのマルチプロセッサ コンピュータが新しく登場した短い時期があり、ソフトウェアを設計する正しい方法は、すべてのオブジェクトがオブジェクト指向プログラムを作成することであると考えるのが流行でした。モニター。
それほど有用なアイデアではなかったことが判明しましたが、その短い瞬間がたまたま Java プログラミング言語が発明されたまさにその時でした。
これは、これらのメソッドはスレッド間通信用であり、ロックを使用してスレッド間通信が行われるためですが、ロックはオブジェクトに関連付けられているため、オブジェクトクラスにあります。
私はそれを簡単な方法で言います:
wait() または notify() を呼び出すには、オブジェクト モニターを所有する必要があります。これは、wait() または notify() が同期ブロックに存在する必要があることを意味します。
synchronized(monitorObj){
monitorObj.wait() or even notify
}
それが、これらのメソッドがオブジェクトクラスに存在する理由です
Wait メソッドと Notify メソッドは、Java の 2 つのスレッド間の通信に使用されます。したがって、Object クラスは、Java のすべてのオブジェクトでそれらを使用できるようにするための正しい場所です。
もう 1 つの理由は、ロックがオブジェクト単位で利用できるようになっていることです。スレッドはロックが必要であり、ロックを待機します。どのスレッドがロックを保持しているかはわかりません。代わりに、ロックが何らかのスレッドによって保持されていることを知っているだけであり、どのスレッドが同期ブロック内にあるかを知り、解放するように要求する代わりに、ロックを待機する必要があります。ロック
待機と通知の説明については、こちらをお読みください。
ただし、アプリケーションではこれらを避け、新しいjava.util.concurrentパッケージを使用することをお勧めします。