java.lang.Object.wait() メソッド, java.lang.Object.notify() メソッド, 及び java.lang.Object.notifyAll() メソッドは, java.lang.Object クラスのネイティブメソッドとして実装されている. これらのメソッドを呼び出すとそれぞれ以下の CVMI 関数が呼び出される.
Method | CVMI function |
---|---|
java.lang.Object.wait() | JVM_MonitorWait() |
java.lang.Object.notify() | JVM_MonitorNotify() |
java.lang.Object.notifyAll() | JVM_MonitorNotifyAll() |
((cite: jdk/src/share/native/java/lang/Object.c))
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
なお, wait() 処理が必要とする「待機しているスレッドの管理」用のデータ構造は inflated 状態にしか存在しない. このため, wait()/notify()/notifyAll() が呼び出された場合, ロック状態は強制的に inflated 状態になる.
wait() が呼ばれると, stack-locked や inflated (locked) から inflated (unlocked) に遷移する.
wait() はロックを取得しているスレッドからしか呼び出せないと規程されているため, neutral や inflated (unlocked) 状態で呼ばれると IllegalMonitorException が発生する.
notify()/notifyAll() は inflated (locked) で実行され, 状態遷移はしない.
より具体的にいうと, wait()/notify() の待ちキューは ObjectMonitor オブジェクトの _WaitSet フィールドで管理している. _WaitSet は ObjectWaiter オブジェクトで構成された doubly linked list であり, 以下のように使用される (See: ObjectMonitor).
wait() メソッドは, 呼び出したスレッドを _WaitSet に登録した後, 一時停止(park())させる.
notify()/notifyAll() は, _WaitSet 中のスレッドを _EntryList か _cxq に移動させる.
(EntryList と _cxq はロック解放を待っているスレッド用の待ち行列 (See: here for details). どちらに移動するかは KnobMoveNotifyee の値に応じて決まる)
移動されたスレッドは, それ以降のロック解放処理時(monitorexit バイトコード実行時/synchronized メソッドからの脱出時)に起床(unpark())される.
なお, 現状では notify() と notifyAll() の実装は非常に似ている. 違いは, notify() は _WaitSet から 1つスレッドを選んで移動させるが, notifyAll() は _WaitSet 中の全スレッドを移動させるという点だけ.
また, wait()/notify()/notifyAll() では, timeout や interrupt による起床と, 実際に notify されたことによる起床を区別するために ObjectWaiter オブジェクトの _notified というフィールドを使っている. このフィールドは ObjectWaiter オブジェクトが生成された直後は 0 だが, ObjectMonitor::notify() で起こされると 1 になる (つまり, 起床した際に _notified がゼロのままなら notify() 以外の原因による起床) (See: ObjectWaiter).
正確には, java.lang.Object.wait() はオーバーロードされており 3つのバージョンが存在する.
ネイティブメソッドとして定義されているのは java.lang.Object.wait(long timeout). その他の 2つ (java.lang.Object.wait(), java.lang.Object.wait(long timeout, int nanos)) はそのラッパーになっている.
JVM_MonitorWait() -> ObjectSynchronizer::wait() -> BiasedLocking::revoke_and_rebias() -> ObjectSynchronizer::inflate() -> ObjectMonitor::wait() -> CHECK_OWNER() -> ObjectMonitor::AddWaiter() -> ObjectMonitor::exit() -> (See: here for details) -> os::PlatformEvent::park() or os::PlatformEvent::park(jlong millis) -> (See: here for details) -> ObjectMonitor::DequeueSpecificWaiter() -> ObjectMonitor::enter() or ObjectMonitor::ReenterI() -> (See: here for details)
java.lang.Object.wait() -> java.lang.Object.wait(long timeout) -> (上述) java.lang.Object.wait(long timeout, int nanos) -> java.lang.Object.wait(long timeout) -> (上述)
JVM_MonitorNotify() -> ObjectSynchronizer::notify() -> ObjectMonitor::notify() -> CHECK_OWNER() -> ObjectMonitor::DequeueWaiter()
JVM_MonitorNotifyAll() -> ObjectSynchronizer::notifyall() -> ObjectMonitor::notifyAll() -> CHECK_OWNER() -> ObjectMonitor::DequeueWaiter()
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.