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
.
This Question appears to be based on some incorrect assumptions / statements.
The Java ReentrantLock
class does not have an await
or signal
method.
That means that consumers
is (most likely) not a ReentrantLock
... and nothing in your code snippet calls signal
(or singnal
(sic)).
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:
It might not be a condition for the Lock
that is denoted by lock
.
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.