title: How to avoid IllegalMonitorStateException when using lockInterruptibly on Reentrantlock
body: <p>I want to replace a <code>syncronized</code> block with a <code>ReentrantLock</code> to support interruption of waiting for the lock. For this, I use the <code>lockInterruptibly()</code> method and the idiomatic try/finally block:</p>
  
  <pre><code>private ReentrantLock lock = new ReentrantLock();
  
  try
  {
    lock.lockInterruptably();
  }
  catch( InterruptedException e )
  {
    Thread.currentThread.interrupt();
  }
  finally
  {
    lock.unlock();
  }
  </code></pre>
  
  <p>The problem is that the finally ofcourse also happens when the InterruptedException happens. This results in an <code>IllegalMonitorStateException</code>, because the lock is not held by the current thread.</p>
  
  <p>This simple program proves this:</p>
  
  <pre><code>public class LockTest
  {
  public static void main( String[] args )
  {
      System.out.println("START");
  
      Thread interruptThread = new Thread( new MyRunnable( Thread.currentThread() ) );
      interruptThread.start();
      ReentrantLock lock = new ReentrantLock();
  
      Thread takeLockThread = new Thread( new TakeLockRunnable( lock ) );
      takeLockThread.start();
  
      try
      {
          Thread.sleep( 500 );
          System.out.println("Trying to take lock on thread " + Thread.currentThread().getName());
          lock.lockInterruptibly();
      }
      catch (InterruptedException e)
      {
          e.printStackTrace();
      }
      finally {
          lock.unlock();
      }
  
      System.out.println( "DONE");
  }
  
  private static class MyRunnable implements Runnable
  {
      private Thread m_thread;
  
      private MyRunnable( Thread thread)
      {
          m_thread = thread;
      }
  
      @Override
      public void run()
      {
          try
          {
              Thread.sleep( 1000 );
          }
          catch (InterruptedException e)
          {
              // ignore
          }
          System.out.println( "Interrupting thread " + m_thread.getName() );
          m_thread.interrupt();
      }
  }
  
  private static class TakeLockRunnable implements Runnable
  {
      private ReentrantLock m_lock;
  
      public TakeLockRunnable( ReentrantLock lock )
      {
          m_lock = lock;
      }
  
      @Override
      public void run()
      {
          try
          {
              System.out.println("Taking lock on thread " + Thread.currentThread().getName());
              m_lock.lock();
              Thread.sleep( 20000 );
          }
          catch (Exception e)
          {
              e.printStackTrace();
          }
          finally {
              m_lock.unlock();
          }
      }
  }
  }
  </code></pre>
  
  <p>It prints this output:</p>
  
  <pre>
  START
  Taking lock on thread Thread-1
  Trying to take lock on thread main
  java.lang.InterruptedException
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:877)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1201)
      at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312)
      at LockTest.main(LockTest.java:25)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
  Exception in thread "main" java.lang.IllegalMonitorStateException
      at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:127)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1239)
      at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:431)
      at LockTest.main(LockTest.java:32)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
  Interrupting thread main
  </pre>
  
  <p>Any idea on what the best way is to avoid this?</p>