Java ReentrantLock.unlock/await()/signal() not throwing IllegalMonitorStateException

匿名 (未验证) 提交于 2019-12-03 10:24:21

问题:

Where am I going wrong? Even though my consumer Thread is not holding the lock, the program is not throwing IllegalMonitorStateException for any of the lock calls (unlock/await/signal).

Update:

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()

As per Java Doc. public void unlock() Attempts to release this lock. If the current thread is the holder of this lock then the hold count is decremented. If the hold count is now zero then the lock is released. If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.

回答1:

This Question appears to be based on some incorrect assumptions / statements.

  1. The Java ReentrantLock class does not have an await or signal method.

  2. That means that consumers is (most likely) not a ReentrantLock ... and nothing in your code snippet calls signal (or singnal (sic)).

  3. According to the javadoc, the ReentrantLock lock and unlock methods do not throw IllegalMonitorStateException. And I wouldn't expect them to, because the lock and unlock methods are not operating as primitive monitors / mutexes.

AFAIK, the only way to get that exception out of a Lock object would be to use the primitive mutex operations wait and notify ... which seems a perverse use of the Lock object. (If you want to use those operations, any object will suffice, including a plain Object instance.)

The Lock classes are designed to provide locking that is orthogonal to Java primitive locks, and not constrained to be strictly block-structured. They do not provide directly provide await and signal. If you want that, you need to create a Condition; e.g. using Lock.newCondition(). Note that the Condition.await and signal methods typically will throw IllegalMonitorStateException if the current thread doesn't hold the Lock ... but that behaviour is implementation specific; see the javadoc.


So assuming that consumers is a Condition, then there are a couple of reasons why it might not be throwing the exception:

  1. It might not be a condition for the Lock that is denoted by lock.

  2. The actual Lock class may provide Condition objects that don't require the lock to be held ...

Unfortunately, your code snippet is missing some vital clues that would address those points.


UPDATE

I converted your code into something that I could run:

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();             }         }     } } 

When I run that, I see a IllegalMonitorStateException at the unlock.

When I comment out the unlock() I see IllegalMonitorStateException at the await.

In hindsight, it is clear what it happening. The IllegalMonitorStateException is thrown by await in both cases, but when you call unlock() in the finally block, that throws ANOTHER IllegalMonitorStateException ... so you don't see the first one.

In short, the methods are behaving exactly as the spec says they should.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!