为什么这个测试程序会导致 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");
}

输出:

  

成功

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top