我有这段代码
Lock lock = new ReentrantLock();
void someMethod() {
try {
if (lock.tryLock(120, TimeUnit.SECONDS)) {
// do stuff
} else {
// timed out
throw new RuntimeException("timeout");
}
} finally {
lock.unlock();
}
}
除非超时时工作正常。由于超时的线程不拥有锁,因此抛出IllegalMonitorStateException
。 isHeldByCurrentThread
界面中没有Lock
。如果我不想投射到ReentrantLock
,我必须使用丑陋的东西
...
} finally {
if (lock.tryLock()) {
lock.unlock();
lock.unlock(); // twice because tryLock is called twice
}
}
或
...
} finally {
if ( !timeout ) {
lock.unlock();
}
}
有更好的选择吗?感谢
答案 0 :(得分:2)
只有获得锁定才能解锁:
if (lock.tryLock(120, TimeUnit.SECONDS)) {
try {
// Do stuff.
} finally {
lock.unlock();
}
}
请注意:
lock()
的调用的锁定被中断。您应该始终在try
。答案 1 :(得分:0)
try-with-resources 是另一种选择(除了Andy的回答),但Lock
不是AutoCloseable
。
因此,您可以按照here in another SO question和here的说明编写一个包装器,然后您可以在此包装器中使用try-with-resource。
如果您不打算在应用程序的多个位置使用类似的构造,可能不值得。
编辑:阐述解决Sotirios Delimanolis问题的答案。
在我看来,如果无法获取锁定,OP想要抛出RuntimeException
,并且对finally
块中的锁定关闭感到困惑,因为它可能会抛出IllegalMonitorStateException
线程尚未保持锁定。
使用Lock
可让您在程序员想要的任何地方(不一定在try块的末尾或方法结束时)灵活地unlock
& synchronized
关键字缺少灵活性,但根据OP的代码段,似乎他会在完成立即try
阻止之后解锁,因此AutoCloseable
有意义。
以下代码解决了这两个问题,
包装类
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class CloseableReentrantLock extends ReentrantLock implements
AutoCloseable {
private static final long serialVersionUID = 1L;
public CloseableReentrantLock timedLock() throws InterruptedException{
if(this.tryLock(120, TimeUnit.SECONDS))
return this;
else
throw new RuntimeException("timeout");
}
@Override
public void close() throws Exception {
this.unlock();
}
}
<强>客户端强>
try(CloseableReentrantLock lock = new CloseableReentrantLock().timedLock())
{
//do stuff here
}
锁定获取的场景:没有什么特别的事情,在try-with-resource块和解锁后调用close
方法。这或多或少是synchronized
阻止工作的方式,但您无法获得synchronized
的等待时间选项,但finally
代码混乱&amp;程序员错过代码unlock
&amp; finally
不存在syncronized
,Closeable
包装的情况也是如此。
无法获取锁定:在此方案中,由于资源未在try-with-resource和尝试使用资源本身中成功获取抛出异常,将不会在此资源上调用close
,因此IllegalMonitorStateException
将不会出现。
请参阅this question and accepted answer,了解 try-with-resource 本身的例外情况。
此示例代码进一步说明了这一点,
public class TryResource implements AutoCloseable{
public TryResource getResource(boolean isException) throws Exception{
if ( isException) throw new Exception("Exception from closeable getResource method");
else return this;
}
public void doSomething() throws Exception {
System.out.println("In doSomething method");
}
@Override
public void close() throws Exception {
System.out.println("In close method");
throw new Exception("Exception from closeable close method");
}
}
和客户,
public class TryResourceClient {
public static void main(String[] args) throws Exception {
try (TryResource resource = new TryResource().getResource(true)){
resource.doSomething();
}
}
}