Why am I getting IllegalMonitorStateException?

12,895

Solution 1

The documentation is pretty clear:

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.

So the thread which is trying to unlock isn't the holder of the lock. We can't tell why you expected it to be the same thread without seeing more of your code.

Solution 2

I know this question is more than a year old, but I was facing the same problem and the solution turned out to be not another Thread that was holding the Lock somehow but basically a very simple mistake and the inner details of a ReentrantLock. If we look at the implementation of tryRelease:

protected final boolean tryRelease(int releases) {
  int c = getState() - releases;
  if (Thread.currentThread() != getExclusiveOwnerThread())
     throw new IllegalMonitorStateException();
  ..
  if (c == 0) {
    ..
    setExclusiveOwnerThread(null);
  }
  ..
}

If the release-count drops to zero, the exclusiveOwnerThread is set to null. And if you afterwards try to release the lock once more, you're not the exclusiveOwnerThread anymore, since your Thread is unlikely to be null. So one simple .unlock() too much can lead to this (in this situation rather confusing) Exception.

Share:
12,895
Kelsey Abreu
Author by

Kelsey Abreu

Updated on August 12, 2022

Comments

  • Kelsey Abreu
    Kelsey Abreu over 1 year

    I get the following Exception being thrown when I try to unlock an object.

    Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
        at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
        at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
        at Pipe.unlock(Pipe.java:21)
        at Station.doWork(Station.java:81)
        at Station.run(Station.java:66)
        at java.lang.Thread.run(Unknown Source)
    

    All that Pipe.unlock is doing is the following:

    public void unlock(){
       accessLock.unlock();
    }
    

    Where accessLock is an ReentrantLock

    Do you know where the issue could be?

    EDIT:

    This is the run method in Station

    if(Pipes[inConnection].accessLock.tryLock()){
        System.out.println("Station "+ StationNumber+": granted access to pipe "+inConnection+".");
    
    //This is just a way for me to keep track if both pipes have been granted
                if(connected<0)
                    connected=inConnection;
                else
                    connected+=inConnection;
    }
    
    
    if(Pipes[outConnection].accessLock.tryLock()){
                System.out.println("Station "+ StationNumber+": granted access to pipe "+outConnection+".");
    
        //This is just a way for me to keep track if both pipes have been granted
        if(connected<0)
            connected=outConnection;
        else
            connected+=outConnection;   
    }
    
    
            doWork();
    

    While this is the doWork method:

    private void doWork() {
        if(connected==inConnection+outConnection){
            System.out.println("Station "+StationNumber+": successfully flows "+inConnection+".");
            System.out.println("Station "+StationNumber+": successfully flows "+outConnection+".");
    
            Pipes[inConnection].unlock();
            System.out.println("Station "+StationNumber+": released access to pipe "+inConnection+".");
    
            Pipes[outConnection].unlock();
            System.out.println("Station "+StationNumber+": released access to pipe "+outConnection+".");
    
            try {
                Thread.sleep(rand.nextInt(200));
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            WorkLoad--;
        }else if(connected >=0 ){
            Pipes[connected].unlock();
            System.out.println("Station "+StationNumber+": released access to pipe "+connected);
    
        }
    
        connected=-1;
    }