我想用syncronized
替换ReentrantLock
块以支持等待锁定的中断。为此,我使用lockInterruptibly()
方法和惯用的try / finally块:
private ReentrantLock lock = new ReentrantLock();
try
{
lock.lockInterruptably();
}
catch( InterruptedException e )
{
Thread.currentThread.interrupt();
}
finally
{
lock.unlock();
}
问题是当InterruptedException发生时,最终的当然也会发生。这导致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
有什么最好的方法可以避免这个?
答案 0 :(得分:19)
lockInterruptibly()
调用应该在外面 finally块。请注意,这总是尝试使用Lock
API(无论您使用lock()
还是lockInterruptibly()
),因为不想要“解锁” “除非你获得锁定,否则就会工作。
try {
lock.lockInterruptibly();
try {
// do locked work here
} finally {
lock.unlock();
}
} catch( InterruptedException e ) {
Thread.currentThread.interrupt();
}
答案 1 :(得分:2)
只需使用boolean-flag就可以解决这个问题:
private ReentrantLock lock = new ReentrantLock();
boolean lockAcquired = false;
try
{
lock.lockInterruptably();
lockAcquired = true;
}
catch( InterruptedException e )
{
Thread.currentThread.interrupt();
}
finally
{
if(lockAcquired)
{
lock.unlock();
}
}