为什么notifyAll()在Integer上同步时会引发IllegalMonitorStateException?

时间:2008-11-03 23:33:55

标签: java synchronization notify illegalmonitorstateexcep

为什么此测试程序会产生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)

4 个答案:

答案 0 :(得分:54)

您已正确注意到必须从同步块中调用notifyAll

但是,在您的情况下,由于自动装箱,您同步的对象与您在notifyAll上调用的实例不同。实际上,新的递增foo实例仍然局限于堆栈,并且在wait调用中不可能阻止其他线程。

您可以实现自己的可变计数器,在该计数器上执行同步。根据您的应用程序,您可能还会发现AtomicInteger符合您的需求。

答案 1 :(得分:3)

你也应该谨慎地锁定或通知可以由JVM实现的String和Integer之类的对象(以防止创建大量表示整数1或字符串“”的对象。

答案 2 :(得分:3)

增加整数会使旧的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

答案 3 :(得分:1)

正如erickson所指出的那样,没有postincrement运算符的代码可以正常工作:

static Integer foo = new Integer(1);

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

输出:

  

成功