gpt4 book ai didi

java - 在 Reentrantlock 上使用 lockInterruptibly 时如何避免 IllegalMonitorStateException

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:41:36 25 4
gpt4 key购买 nike

我想用 ReentrantLock 替换 syncronized block 以支持中断等待锁。为此,我使用了 lockInterruptibly() 方法和惯用的 try/finally block :

private ReentrantLock lock = new ReentrantLock();

try
{
lock.lockInterruptably();
}
catch( InterruptedException e )
{
Thread.currentThread.interrupt();
}
finally
{
lock.unlock();
}

问题是 finally 当然也会在 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();
}
}
}
}

它打印这个输出:

STARTTaking lock on thread Thread-1Trying to take lock on thread mainjava.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

知道避免这种情况的最佳方法是什么吗?

最佳答案

lockInterruptibly() 调用应该在 finally block 的外部。请注意,这总是尝试使用 Lock API(无论您使用 lock() 还是 lockInterruptibly()),因为您 除非您已获得锁,否则不想进行“解锁”工作。

try {
lock.lockInterruptibly();
try {
// do locked work here
} finally {
lock.unlock();
}
} catch( InterruptedException e ) {
Thread.currentThread.interrupt();
}

关于java - 在 Reentrantlock 上使用 lockInterruptibly 时如何避免 IllegalMonitorStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8897449/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com