超时解锁 lock.tryLock
unlocking a lock.tryLock with timeout
我有这个代码
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
。 Lock
界面中没有isHeldByCurrentThread
。如果我不想转换为 ReentrantLock
,我必须使用一些丑陋的东西
...
} finally {
if (lock.tryLock()) {
lock.unlock();
lock.unlock(); // twice because tryLock is called twice
}
}
或
...
} finally {
if ( !timeout ) {
lock.unlock();
}
}
还有更好的选择吗?谢谢
只有在获得锁后才能解锁:
if (lock.tryLock(120, TimeUnit.SECONDS)) {
try {
// Do stuff.
} finally {
lock.unlock();
}
}
注意:
- There is an example like this in the Javadoc;
- 这个习语与使用超时没有任何关系:你不想解锁对
lock()
的调用被中断的锁。您应该始终在 try
. 外部获取锁,但紧接在之前
try-with-resources 是另一种选择(除了 Andy 的回答),但 Lock
不是 AutoCloseable
。
因此您可以按照说明编写包装器 here in another SO question and here 然后您可以将 try-with-resource 与此包装器一起使用。
如果您不打算在应用程序的多个位置使用类似的构造,那么这可能是不值得的。
编辑: 详细说明解决 Sotirios Delimanolis 关注的问题的答案。
在我看来,如果无法获取锁,OP 想抛出 RuntimeException
并且对 finally
块中的锁关闭感到困惑,因为它可能会抛出 IllegalMonitorStateException
如果线程尚未持有锁。
使用 Lock
可以让你在程序员想要的任何地方(不一定是在 try 块的末尾或方法的末尾)灵活地 unlock
并且 unlock
中缺少灵活性 synchronized
关键字,但根据 OP 的代码片段,他似乎会在完成立即 try
块后立即解锁,因此 AutoCloseable
是有道理的。
下面的代码解决了这两个问题,
包装器class
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())
{
//在这里做事<br>
}
Lock Acquired Scenario:没有什么特别的事情发生,close
方法在 try-with-resource 块和锁解锁后被调用。这或多或少是 synchronized
块的工作方式,但是您无法使用 synchronized
获得等待时间选项,但是 finally
代码混乱并且程序员有可能错过代码 unlock
& finally
与 syncronized
不存在, Closeable
包装器也是如此。
Lock can't be Acquired : 在这种情况下,由于在 try-with-resource 和 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();
}
}
}
我有这个代码
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
。 Lock
界面中没有isHeldByCurrentThread
。如果我不想转换为 ReentrantLock
,我必须使用一些丑陋的东西
...
} finally {
if (lock.tryLock()) {
lock.unlock();
lock.unlock(); // twice because tryLock is called twice
}
}
或
...
} finally {
if ( !timeout ) {
lock.unlock();
}
}
还有更好的选择吗?谢谢
只有在获得锁后才能解锁:
if (lock.tryLock(120, TimeUnit.SECONDS)) {
try {
// Do stuff.
} finally {
lock.unlock();
}
}
注意:
- There is an example like this in the Javadoc;
- 这个习语与使用超时没有任何关系:你不想解锁对
lock()
的调用被中断的锁。您应该始终在try
. 外部获取锁,但紧接在之前
try-with-resources 是另一种选择(除了 Andy 的回答),但 Lock
不是 AutoCloseable
。
因此您可以按照说明编写包装器 here in another SO question and here 然后您可以将 try-with-resource 与此包装器一起使用。
如果您不打算在应用程序的多个位置使用类似的构造,那么这可能是不值得的。
编辑: 详细说明解决 Sotirios Delimanolis 关注的问题的答案。
在我看来,如果无法获取锁,OP 想抛出 RuntimeException
并且对 finally
块中的锁关闭感到困惑,因为它可能会抛出 IllegalMonitorStateException
如果线程尚未持有锁。
使用 Lock
可以让你在程序员想要的任何地方(不一定是在 try 块的末尾或方法的末尾)灵活地 unlock
并且 unlock
中缺少灵活性 synchronized
关键字,但根据 OP 的代码片段,他似乎会在完成立即 try
块后立即解锁,因此 AutoCloseable
是有道理的。
下面的代码解决了这两个问题,
包装器class
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())
{
//在这里做事<br>
}
Lock Acquired Scenario:没有什么特别的事情发生,close
方法在 try-with-resource 块和锁解锁后被调用。这或多或少是 synchronized
块的工作方式,但是您无法使用 synchronized
获得等待时间选项,但是 finally
代码混乱并且程序员有可能错过代码 unlock
& finally
与 syncronized
不存在, Closeable
包装器也是如此。
Lock can't be Acquired : 在这种情况下,由于在 try-with-resource 和 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();
}
}
}