为什么notifyAll()在Integer上同步时会引发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。
以下是erickson建议的AtomicInteger的实现。在这个例子中foo.notifyAll();不会产生java.lang.IllegalMonitorStateException因为当foo.incrementAndGet()时没有刷新AtomicInteger对象;跑了。
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
正如erickson所指出的那样,没有postincrement运算符的代码可以正常工作:
static Integer foo = new Integer(1);
public static void main(String[] args) {
synchronized (foo) {
foo.notifyAll();
}
System.out.println("Success");
}
输出:
成功
不隶属于 StackOverflow