English 中文(简体)
为什么在整数上同步时,notifyAll()会引发IllegalMonitorStateException(非法监视器状态异常)?
原标题:
  • 时间:2008-11-03 23:33:55
  •  标签:

为什么这个测试程序会产生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符合你的需求。

问题回答

你还应该警惕在String和Integer这样的对象上进行锁定或通知,因为JVM可能会对其进行池化(为了防止创建代表整数1或字符串""的大量对象)。

递增整数会使旧foo消失,并被一个全新的foo对象替换,这个对象与以前的foo变量不同步。

这是erickson上面建议的AtomicInteger的实现。在这个例子中,当运行foo.incrementAndGet()时,foo.notifyAll()不会产生java.lang.IllegalMonitorStateException,因为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

正如埃里克森所指出的那样,没有后增运算符的代码可以无错误运行:

static Integer foo = new Integer(1);

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

输出

成功





相关问题
热门标签