使用超时解锁lock.tryLock

时间:2017-07-18 14:11:10

标签: java java.util.concurrent

我有这段代码

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();
    }
}

除非超时时工作正常。由于超时的线程不拥有锁,因此抛出IllegalMonitorStateExceptionisHeldByCurrentThread界面中没有Lock。如果我不想投射到ReentrantLock,我必须使用丑陋的东西

...
} finally {
    if (lock.tryLock()) {
        lock.unlock();
        lock.unlock(); // twice because tryLock is called twice
    }
}

...
} finally {
    if ( !timeout ) {
        lock.unlock();
    }
}

有更好的选择吗?感谢

2 个答案:

答案 0 :(得分:2)

只有获得锁定才能解锁:

if (lock.tryLock(120, TimeUnit.SECONDS)) {
  try {
    // Do stuff.
  } finally {
    lock.unlock();
  }
}

请注意:

答案 1 :(得分:0)

try-with-resources 是另一种选择(除了Andy的回答),但Lock不是AutoCloseable

因此,您可以按照here in another SO questionhere的说明编写一个包装器,然后您可以在此包装器中使用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不存在syncronizedCloseable包装的情况也是如此。

无法获取锁定:在此方案中,由于资源未在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();
        }
    }

}