超时解锁 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();
    }
}

这工作正常,除非超时。由于超时的线程不拥有锁,因此抛出IllegalMonitorStateExceptionLock界面中没有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();
  }
}

注意:

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 & finallysyncronized 不存在, 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();
        }
    }

}