プログラムに Java でマルチスレッドを使用しています。スレッドを正常に実行しましたが、使用しているときに をThread.wait()
スローしていjava.lang.IllegalMonitorStateException
ます。通知されるまでスレッドを待機させるにはどうすればよいですか?
11 に答える
synchronized
が機能するには、ブロック内にいる必要がありますObject.wait()
。
また、古い学校のスレッド化パッケージではなく、同時実行パッケージを検討することをお勧めします。それらはより安全で、作業がはるかに簡単です。
編集
Object.wait()
オブジェクトのロックを保持せずにアクセスしようとすると例外が発生するので、あなたが意図していると思いました。
wait
は で定義されており、それでは定義されObject
ていませんThread
。オンのモニターThread
は少し予測不能です。
すべての Java オブジェクトにはモニターがありますが、通常は専用のロックを使用することをお勧めします。
private final Object lock = new Object();
名前付きクラスを使用すると、小さなメモリ コスト (プロセスごとに約 2K) で、診断を読みやすくすることができます。
private static final class Lock { }
private final Object lock = new Lock();
オブジェクトをwait
またはnotify
/にするには、ステートメントnotifyAll
でロックを保持する必要があります。synchronized
また、ウェイクアップ状態を確認するためのループが必要になりwhile
ます (理由を説明するスレッドに関する適切なテキストを見つけてください)。
synchronized (lock) {
while (!isWakeupNeeded()) {
lock.wait();
}
}
通知するには:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
マルチスレッド化を開始するときは、Java 言語とjava.util.concurrent.locks
ロック (および) の両方を理解する価値があります。java.util.concurrent.atomic
ただし、java.util.concurrent
できる限りデータ構造を使用してください。
このスレッドがほぼ 2 年前のものであることは知っていますが、同じ問題でこの Q/A セッションにも参加したので、まだこれを閉じる必要があります...
この illegalMonitorException の定義を何度も読んでください...
IllegalMonitorException は、スレッドがオブジェクトのモニターで待機しようとしたことを示すか、指定されたモニターを所有せずにオブジェクトのモニターで待機している他のスレッドに通知するためにスローされます。
この行は、2 つの状況のいずれかが発生すると、IllegalMonitorException が発生すると繰り返し述べています。
1> 指定されたモニターを所有せずに、オブジェクトのモニターを待機します。
2> 指定されたモニターを所有せずに、オブジェクトのモニターで待機している他のスレッドに通知します。
答えを得た人もいるかもしれません...誰もそうではないので、2つのステートメントを確認してください....
同期 (オブジェクト)
object.wait()
両方のオブジェクトが同じである場合...その後、 illegalMonitorException は発生しません。
IllegalMonitorException の定義をもう一度読んでください。もう一度忘れることはありません...
あなたのコメントに基づいて、あなたは次のようなことをしているようです:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
3 つの問題があります。
他の人が言った
obj.wait()
ように、現在のスレッドがプリミティブロック/ミューテックスを保持している場合にのみ呼び出すことができますobj
。現在のスレッドがロックを保持していない場合、表示されている例外が発生します。呼び出しは、
thread.wait()
あなたが期待しているように見えることをしません。具体的には、指定されたスレッドを待機さthread.wait()
せません。むしろ、他のスレッドがorを呼び出すまで、現在のスレッドを待機させます。thread.notify()
thread.notifyAll()
実際には、
Thread
インスタンスを一時停止したくない場合に強制的に一時停止する安全な方法はありません。(Java がこれに最も近いのは非推奨のThread.suspend()
メソッドですが、Javadoc で説明されているように、そのメソッドは本質的に安全ではありません。)新しく開始したものを一時停止したい場合、インスタンスを作成し、ラッチでスレッドを呼び出して
Thread
一時停止するのが最善の方法です。次に、メインスレッドはラッチを呼び出して、一時停止したスレッドを続行させます。CountdownLatch
await()
countDown()
Thread
オブジェクトをロック/ミューテックスとして使用すると、前のポイントと直交し、問題が発生する可能性があります。たとえば、Javadoc にThread::join
は次のように書かれています。this.wait
この実装では、を条件とする呼び出しのループを使用しますthis.isAlive
。スレッドが終了すると、this.notifyAll
メソッドが呼び出されます。wait
アプリケーションでは、インスタンスで 、notify
、またはnotifyAll
を使用しないことをお勧めしThread
ます。
あなたがコードを投稿していないので、私たちは暗闇の中で作業しています. 例外の詳細は?
スレッド内またはスレッド外から Thread.wait() を呼び出していますか?
IllegalMonitorStateException の javadoc によると、次のようになっているため、これをお願いします。
スレッドがオブジェクトのモニターで待機しようとしたことを示すか、指定されたモニターを所有せずにオブジェクトのモニターで待機している他のスレッドに通知するためにスローされます。
この答えを明確にするために、スレッドを待機するこの呼び出しは、同期ブロック内から呼び出されたにもかかわらず、IllegalMonitorStateException もスローします。
private static final class Lock { }
private final Object lock = new Lock();
@Test
public void testRun() {
ThreadWorker worker = new ThreadWorker();
System.out.println ("Starting worker");
worker.start();
System.out.println ("Worker started - telling it to wait");
try {
synchronized (lock) {
worker.wait();
}
} catch (InterruptedException e1) {
String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
System.out.println (msg);
e1.printStackTrace();
System.out.flush();
}
System.out.println ("Worker done waiting, we're now waiting for it by joining");
try {
worker.join();
} catch (InterruptedException ex) { }
}
Thread.wait() 呼び出しは、Thread.class オブジェクトで同期するコード内で意味があります。私はそれがあなたが意図したものではないと思います。
あなたが尋ねる
通知されるまでスレッドを待機させるにはどうすればよいですか?
現在のスレッドのみを待機させることができます。他のスレッドは、同意する場合にのみ静かに待機するように依頼できます。
何らかの条件を待ちたい場合は、ロックオブジェクトが必要です-Thread.classオブジェクトは非常に悪い選択です-それはシングルトンAFAIKであるため、同期することは危険です(スレッド静的メソッドを除く)。
同期と待機の詳細は、Tom Hawtin によって既に説明されています。
java.lang.IllegalMonitorStateException
同期されていないオブジェクトを待機しようとしていることを意味します。これは違法です。