整数で同期するときにnotifyAll()がIllegalMonitorStateExceptionを発生させるのはなぜですか?
-
06-07-2019 - |
質問
このテストプログラムが 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");
}
出力:
成功
所属していません StackOverflow