41

このテスト プログラムの結果はなぜjava.lang.IllegalMonitorStateExceptionですか?

public class test {
    static Integer foo = new Integer(1);
    public static void main(String[] args) {
        synchronized(foo) {
            foo++;
            foo.notifyAll();
        }
        System.err.println("Success");
    }
}

結果:

Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notifyAll(Native Method)
        at test.main(test.java:6)
4

4 に答える 4

58

notifyAll同期ブロックから呼び出す必要があることに正しく注意しました。

ただし、あなたの場合、自動ボクシングのため、同期したオブジェクトは呼び出しnotifyAllたインスタンスとは異なります。実際、インクリメントされた新しいインスタンスはまだスタックに限定されており、呼び出しfooで他のスレッドがブロックされる可能性はありません。wait

同期が実行される独自の可変カウンターを実装できます。アプリケーションによっては、AtomicIntegerがニーズを満たす場合もあります。

于 2008-11-03T23:37:04.700 に答える
3

整数をインクリメントすると、古いfooが消えて、前のfoo変数と同期されていない新しいオブジェクトfooに置き換えられます。

これは、エリクソンが上で提案したAtomicIntegerの実装です。この例では、foo.notifyAll(); foo.incrementAndGet();のときにAtomicIntegerオブジェクトが更新されないため、java.lang.IllegalMonitorStateExceptionは生成されません。実行されます。

import java.util.concurrent.atomic.AtomicInteger;

public class SynchronizeOnAPrimitive {
    static AtomicInteger foo = new AtomicInteger(1);
    public static void main(String[] args) {
        synchronized (foo) {
            foo.incrementAndGet();
            foo.notifyAll();
        }
        System.out.println("foo is: " + foo);
    }
}

出力:

foo is: 2
于 2011-03-18T21:28:03.613 に答える
3

また、JVM によってインターンされる可能性のある String や Integer などのオブジェクトをロックしたり通知したりしないようにする必要があります (整数 1 または文字列 "" を表す多くのオブジェクトを作成しないようにするため)。

于 2008-11-03T23:47:41.807 に答える
1

エリクソンが指摘したように、ポストインクリメント演算子のないコードはエラーなしで動作します:

static Integer foo = new Integer(1);

public static void main(String[] args) {
    synchronized (foo) {
        foo.notifyAll();
    }
    System.out.println("Success");
}

出力:

成功

于 2008-11-03T23:43:57.243 に答える