Java ReentrantLock.unlock / await()/ signal()不会抛出IllegalMonitorStateException

时间:2014-06-13 04:29:27

标签: java multithreading locking

我哪里错了?即使我的消费者线程没有持有锁,程序也不会为任何锁定调用(unlock / await / signal)抛出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。 public void unlock() 尝试释放此锁定。 如果当前线程是此锁的持有者,则保持计数递减。如果保持计数现在为零,则释放锁定。 If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown

1 个答案:

答案 0 :(得分:2)

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

  1. Java ReentrantLock类没有awaitsignal方法。

  2. 这意味着consumers(很可能)不是ReentrantLock ...而您的代码段中没有任何内容会调用signal(或singnal(sic) ))。

  3. 根据javadoc,ReentrantLock锁定和解锁方法不会抛出IllegalMonitorStateException。而且我不指望它们,因为锁定和解锁方法不是作为原始监视器/互斥体运行。

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

    Lock类旨在提供与Java原始锁正交的锁定,而不是严格限制为块结构。它们不提供直接提供等待和信号。如果你想要,你需要创建一个Condition;例如使用Lock.newCondition()。请注意,如果当前线程不包含IllegalMonitorStateException,则Condition.await和信号方法通常将抛出Lock,但该行为是特定于实现的;请参阅javadoc


    假设consumersCondition,那么有几个原因导致它可能不会抛出异常:

    1. Lock可能不是由lock表示的条件。

    2. 实际的Lock类可能会提供不需要锁定的Condition个对象...

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


      <强>更新

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

      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,但当您在IllegalMonitorStateException区块中调用{{1}}时,会引发另一个{{1}} ...所以你不要看不到第一个。

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

相关问题