我想用ReentrantLock
替換syncronized
塊以支持等待鎖的中斷。對於這一點,我用的是lockInterruptibly()
方法和慣用的try/finally塊:如何避免IllegalMonitorStateException使用lockInterruptibly在可重入鎖
private ReentrantLock lock = new ReentrantLock();
try
{
lock.lockInterruptably();
}
catch(InterruptedException e)
{
Thread.currentThread.interrupt();
}
finally
{
lock.unlock();
}
的問題是,最終當InterruptedException的發生ofcourse也發生了。這導致IllegalMonitorStateException
,因爲該鎖不是由當前線程保持。
這個簡單的程序證明了這一點:
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();
}
}
}
}
它打印輸出:
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
什麼最好的辦法的任何想法是避免這種情況?
任何人都喜歡評論downvote? – jtahlborn 2012-01-17 18:46:53
我第一次使用'isHeldByCurrentThread',但在閱讀完所有評論之後,我認爲這個版本是唯一真正正確的版本。 – 2012-01-18 07:08:00
@WimDeblauwe您提到哪些評論,以及爲什麼您認爲使用'isHeldByCurrentThread'是不正確的? – 2013-01-29 17:38:24