try-with-resources 是另一种选择(除了安迪的回答),但 Lock 不是 AutoCloseable 。
因此您可以按照here in another SO question 和here 的说明编写一个包装器,然后您可以将try-with-resource 与此包装器一起使用。
如果您不打算在应用程序的多个位置使用类似的构造,那么这可能不值得。
编辑: 详细解答以解决 Sotirios Delimanolis 的担忧。
在我看来,如果无法获取锁,OP 想要抛出 RuntimeException,并且对关闭 finally 块中的锁感到困惑,因为如果线程尚未持有锁,它可能会抛出 IllegalMonitorStateException。
使用Lock 可以让您在程序员想要的任何地方灵活使用unlock(不一定是在try 块的末尾或方法的末尾),并且synchronized 关键字中缺少灵活性,但根据OP的代码sn-p,似乎他会在完成立即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
}
锁定获取场景:没有什么特别的事情发生,close 方法在 try-with-resource 块之后被调用并且锁定被解锁。这或多或少是synchronized 块的工作方式,但您无法使用synchronized 获得等待时间选项,但finally 代码混乱和程序员错过代码unlock 和finally 的机会不是syncronized 和 Closeable 包装器的情况也是如此。
无法获取锁:在这种情况下,由于在 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();
}
}
}