このテストプログラムはなぜ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または文字列 ""を表す多くのオブジェクトが作成されるのを防ぐため)。
Integerをインクリメントすると、古い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");
}
出力:
成功