整数で同期するときにnotifyAll()がIllegalMonitorStateExceptionを発生させるのはなぜですか?

StackOverflow https://stackoverflow.com/questions/260337

質問

このテストプログラムが 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)
役に立ちましたか?

解決

notifyAll は同期ブロックから呼び出す必要があることを正しく指摘しました。

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

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

他のヒント

また、JVMによってインターンできるStringやIntegerのようなオブジェクトのロックまたは通知には慎重でなければなりません(整数1または文字列""を表す多くのオブジェクトの作成を防ぐため)。

整数をインクリメントすると、古い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

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

static Integer foo = new Integer(1);

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

出力:

  

成功

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top