持有锁时Java IllegalStateMonitorException

Ric*_*chi 2 java multithreading locking

我在java中编写了一个实现双缓冲区的类.该类有两种方法可以写入两个缓冲区,另一种方法可以清除它们.然后我有三个线程:一个写入第一个缓冲区,另一个写入第二个缓冲区,第三个写入清除缓冲区.

在这里,我粘贴(一段)导致问题的代码(我知道它不正确,但我为了调试目的简化了它):

public void addAlpha(int toAdd){
synchronized (alphaCount) {
    while(alphaCount >= alpha.length){
        try {
        alphaCount.wait();
        } catch (InterruptedException e) {
        }
    }

    alpha[alphaCount] = toAdd;
    alphaCount++;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里我称之为notifyAll():

public void clear(){
    synchronized (alphaCount) {
        alphaCount = 0;
        alphaCount.notifyAll();
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,在addAlpha方法中,我获得了对alphaCount的锁定,测试条件然后等待alphaCount对象.

在clear方法中,我获得了对alphaCount的锁定,并在其上调用notifyAll().在运行时,我得到IllegalStateMonitorException ...

但我真的不知道错误在哪里:我检查了文档和多个论坛,没有任何运气......

谢谢你的时间和你的关注,里克.

Pet*_*rey 7

作为一项规则,你应该将字段用作锁,final否则你可以得到这样的bug.恕我直言你应该做尽可能多的场决赛.;)

synchronized (alphaCount) { // alphaCount == 1 which is locked.
    alphaCount = 0;         // alphaCount == 0 which is not locked.
    alphaCount.notifyAll(); // fails.
}
Run Code Online (Sandbox Code Playgroud)

另外,我不建议使用Integer或String或任何包装类型来锁定.因为有许多令人困惑和令人惊讶的后果.例如

Integer i1 = 127;
Integer i2 = 127; // same object due to the auto-boxing cache.
i1 == i2;

Integer i1 = 128;
Integer i2 = 128; // not the same object.
i1 != i2; // may or may not be the same object depending on the cache size.
Run Code Online (Sandbox Code Playgroud)

另一个问题是你可能会遇到一个完全不相关的库的死锁,这也恰好使用整数作为锁.


解决方案是使用专用的锁定对象.

private final Object alphaCountLock = new Object();
private int alphaCount = 0; // don't use an object when a primitive will do.

synchronized (alphaCountLock ) {
    alphaCount = 0;
    alphaCountLock .notifyAll();
}
Run Code Online (Sandbox Code Playgroud)