1. ホーム

[解決済み】なぜwait()は常に同期ブロックの中になければならないのか?

2022-03-31 02:02:34

質問

を呼び出すには、次のような方法があることは知っています。 Object.wait() この呼び出しは同期ブロック内に配置されなければならず、そうでなければ IllegalMonitorStateException が投げられます。しかし この制限を設ける理由は何ですか? 知っているのは wait() はモニタを解放しますが、なぜ特定のブロックを同期化することで明示的にモニタを獲得し、その後、モニタを解放するために wait() ?

を呼び出すことができた場合、どのような被害が考えられるでしょうか。 wait() 同期ブロックの外側で、呼び出し元のスレッドを一時停止させるというセマンティクスを維持したまま?

解決方法は?

A wait() があるときだけ意味があります。 notify() つまり、常にスレッド間の通信に関係しており、正しく動作させるためには同期が必要なのです。これは暗黙の了解であるべきだと主張することもできますが、次の理由から、それは実際には役に立ちません。

意味的には、決して wait() . ある条件が満たされる必要があり、満たされない場合は満たされるまで待つのです。ですから、実際に行うのは

if(!condition){
    wait();
}

しかし、条件は別のスレッドで設定されているので、これを正しく動作させるためには同期が必要です。

あと2つほど間違っていることがあります。スレッドが待ちをやめたからといって、求めている条件が真であるとは限りません。

  • spurious wakeups(スレッドが一度も通知を受け取らずに待機から目覚めることを意味する)が発生することがある、または

  • 条件が設定されても、待機中のスレッドが目を覚ます(そしてモニターを再取得する)までに、第3のスレッドがその条件を再び偽にすることができる。

このようなケースに対処するために本当に必要なのは 常に のバリエーションがあります。

synchronized(lock){
    while(!condition){
        lock.wait();
    }
}

もっといいのは、同期プリミティブをまったくいじらずに java.util.concurrent パッケージを使用します。