I want to replace the syncronized block with syncronized in ReentrantLock to support interruption of waiting for the lock. To do this, I use the lockInterruptibly() method and the idiomatic try / finally block:
private ReentrantLock lock = new ReentrantLock(); try { lock.lockInterruptably(); } catch( InterruptedException e ) { Thread.currentThread.interrupt(); } finally { lock.unlock(); }
The problem is what ultimately happens as well when an InterruptedException occurs. This raises an IllegalMonitorStateException because the lock is not held by the current thread.
This simple program proves this:
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) {
He prints this output:
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.javahaps12)
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∗97)
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∗97)
at com.intellij.rt.execution.application.AppMain.main (AppMain.java:120)
Interrupting thread main
Any idea what is the best way to avoid this?
source share