168

プログラムに Java でマルチスレッドを使用しています。スレッドを正常に実行しましたが、使用しているときに をThread.wait()スローしていjava.lang.IllegalMonitorStateExceptionます。通知されるまでスレッドを待機させるにはどうすればよいですか?

4

11 に答える 11

184

synchronizedが機能するには、ブロック内にいる必要がありますObject.wait()

また、古い学校のスレッド化パッケージではなく、同時実行パッケージを検討することをお勧めします。それらはより安全で、作業がはるかに簡単です。

編集

Object.wait()オブジェクトのロックを保持せずにアクセスしようとすると例外が発生するので、あなたが意図していると思いました。

于 2009-10-08T11:11:53.913 に答える
57

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できる限りデータ構造を使用してください。

于 2009-10-08T12:06:07.137 に答える
26

このスレッドがほぼ 2 年前のものであることは知っていますが、同じ問題でこの Q/A セッションにも参加したので、まだこれを閉じる必要があります...

この illegalMonitorException の定義を何度も読んでください...

IllegalMonitorException は、スレッドがオブジェクトのモニターで待機しようとしたことを示すか、指定されたモニターを所有せずにオブジェクトのモニターで待機している他のスレッドに通知するためにスローされます。

この行は、2 つの状況のいずれかが発生すると、IllegalMonitorException が発生すると繰り返し述べています。

1> 指定されたモニターを所有せずに、オブジェクトのモニターを待機します。

2> 指定されたモニターを所有せずに、オブジェクトのモニターで待機している他のスレッドに通知します。

答えを得た人もいるかもしれません...誰もそうではないので、2つのステートメントを確認してください....

同期 (オブジェクト)

object.wait()

両方のオブジェクトが同じである場合...その後、 illegalMonitorException は発生しません。

IllegalMonitorException の定義をもう一度読んでください。もう一度忘れることはありません...

于 2012-01-25T10:35:56.157 に答える
6

あなたのコメントに基づいて、あなたは次のようなことをしているようです:

Thread thread = new Thread(new Runnable(){
    public void run() { // do stuff }});

thread.start();
...
thread.wait();

3 つの問題があります。

  1. 他の人が言ったobj.wait()ように、現在のスレッドがプリミティブロック/ミューテックスを保持している場合にのみ呼び出すことができますobj。現在のスレッドがロックを保持していない場合、表示されている例外が発生します。

  2. 呼び出しは、thread.wait()あなたが期待しているように見えることをしません。具体的には、指定されたスレッドを待機さthread.wait() せません。むしろ、他のスレッドがorを呼び出すまで、現在のスレッドを待機させます。thread.notify()thread.notifyAll()

    実際には、Threadインスタンスを一時停止したくない場合に強制的に一時停止する安全な方法はありません。(Java がこれに最も近いのは非推奨のThread.suspend()メソッドですが、Javadoc で説明されているように、そのメソッドは本質的に安全ではありません。)

    新しく開始したものを一時停止したい場合、インスタンスを作成し、ラッチでスレッドを呼び出してThread一時停止するのが最善の方法です。次に、メインスレッドはラッチを呼び出して、一時停止したスレッドを続行させます。CountdownLatchawait()countDown()

  3. Threadオブジェクトをロック/ミューテックスとして使用すると、前のポイントと直交し、問題が発生する可能性があります。たとえば、Javadoc にThread::joinは次のように書かれています。

    this.waitこの実装では、を条件とする呼び出しのループを使用しますthis.isAlive。スレッドが終了すると、this.notifyAllメソッドが呼び出されます。waitアプリケーションでは、インスタンスで 、notify、またはnotifyAllを使用しないことをお勧めしThreadます。

于 2009-10-08T15:21:00.550 に答える
2

あなたがコードを投稿していないので、私たちは暗闇の中で作業しています. 例外の詳細は?

スレッド内またはスレッド外から 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) { }

    }
于 2009-10-08T11:29:13.480 に答える
0

Thread.wait() 呼び出しは、Thread.class オブジェクトで同期するコード内で意味があります。私はそれがあなたが意図したものではないと思います。
あなたが尋ねる

通知されるまでスレッドを待機させるにはどうすればよいですか?

現在のスレッドのみを待機させることができます。他のスレッドは、同意する場合にのみ静かに待機するように依頼できます。
何らかの条件を待ちたい場合は、ロックオブジェクトが必要です-Thread.classオブジェクトは非常に悪い選択です-それはシングルトンAFAIKであるため、同期することは危険です(スレッド静的メソッドを除く)。
同期と待機の詳細は、Tom Hawtin によって既に説明されています。 java.lang.IllegalMonitorStateException同期されていないオブジェクトを待機しようとしていることを意味します。これは違法です。

于 2009-10-08T14:12:07.473 に答える