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