IllegalMonitorStateException

IllegalMonitorStateException

我要去哪里错了?即使我的使用者线程未持有该锁,该程序也不会针对任何锁调用(解锁/等待/信号)抛出IllegalMonitorStateException。

更新:

private final ReentrantLock lock = new ReentrantLock();
private final Condition producers = lock.newCondition();
private final Condition consumers = lock.newCondition();

@Override
public void run() {

    while (true) {
        try {
            //lock.lockInterruptibly();
            try {
                while (sharedResource.isEmpty()) {
                    printErr(name + " : Queue Empty ..");
                    consumers.await(500, TimeUnit.MILLISECONDS);
                }

                String obj = sharedResource.remove(0);
                printOut(name + " : " + obj);
                if (obj.equals(POISON_PILL)) {
                    sharedResource.add(POISON_PILL);
                    // System.err.println(name +" Taking break");
                    break;
                }

                producers.signal();
            } finally {
                lock.unlock();
            }
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // if(debug)System.err.println("Consumer Looping");
    }
}


void java.util.concurrent.locks.ReentrantLock.unlock()

按照Java Doc
公共无效解锁()
尝试释放此锁。
如果当前线程是此锁的持有者,则保留计数将减少。如果保持计数现在为零,则释放锁定。 If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown

最佳答案

该问题似乎基于一些不正确的假设/陈述。


Java ReentrantLock类没有awaitsignal方法。
这意味着consumers(很可能)不是ReentrantLock ...,并且代码段中的任何内容都不会调用signal(或singnal(sic))。
根据javadoc,ReentrantLock锁定和解锁方法不会抛出IllegalMonitorStateException。而且我不希望它们如此,因为lock和unlock方法不能作为原始监视器/互斥体运行。


AFAIK,从Lock对象中获取该异常的唯一方法是使用原始互斥操作waitnotify ...,这似乎是对Lock对象的不正确使用。 (如果要使用这些操作,则任何对象都足够,包括一个普通的Object实例。)

Lock类旨在提供与Java基本锁正交的锁,并且不限于严格的块结构。它们不直接提供等待和信号。如果需要,您需要创建一个Condition;例如使用Lock.newCondition()。注意,如果当前线程不保存IllegalMonitorStateException ...,则Condition.await和signal方法通常将抛出Lock ...但是该行为是实现特定的;参见javadoc



因此,假设consumersCondition,则有几个原因可能导致它未引发异常:


Lock表示的lock可能不是条件。
实际的Lock类可能会提供Condition对象,这些对象不需要保持锁...


不幸的是,您的代码片段缺少一些可以解决这些问题的重要线索。



更新

我将您的代码转换为可以运行的代码:

package test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Lochy {

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition producers = lock.newCondition();
        Condition consumers = lock.newCondition();

        while (true) {
            try {
                try {
                    for (int i = 0; i < 3; i++) {
                        System.out.println("wait " + i);
                        consumers.await(500, TimeUnit.MILLISECONDS);
                    }
                    producers.signal();
                } finally {
                    lock.unlock();
                }
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


运行该命令时,在IllegalMonitorStateException处看到一个unlock

当我注释掉unlock()时,在IllegalMonitorStateException上看到await

事后看来,这很清楚。在两种情况下,IllegalMonitorStateException均由await引发,但是当您在unlock()块中调用finally时,将引发ANOTHER IllegalMonitorStateException ...,因此看不到第一个。

简而言之,这些方法的行为完全符合规范的规定。

10-05 19:52