如何使用锁定包装器进行自动关闭?

时间:2015-08-06 11:02:20

标签: java concurrency try-with-resources autocloseable

我写了以下wrapepr:

public class AutoCloseableLockWrapper implements AutoCloseable, Lock{
    private final Lock lock;
    public AutoCloseableLockWrapper(Lock l) {
        this.lock = l;
    }
    @Override
    public void lock() {
        this.lock.lock();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        lock.lockInterruptibly();
    }

    @Override
    public boolean tryLock() {
        return lock.tryLock();
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return lock.tryLock(time,unit);
    }

    @Override
    public void unlock() {
        lock.unlock();
    }

    @Override
    public Condition newCondition() {
        return lock.newCondition();
    }
    @Override
    public void close() {
        this.lock.unlock();
    }
} 

在我的代码中我使用它:

public class ReadWriteMap implements Map {

    private HashMap map = new HashMap();
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Lock readLock = readWriteLock.readLock();
    private Lock writeLock = readWriteLock.writeLock();

    @Override
    public int size() {
        try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
            autoCloseableLockWrapper.lock();
            return map.size();
        }

    }

    @Override
    public boolean isEmpty() {
        try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
            autoCloseableLockWrapper.lock();
            return map.isEmpty();
        }
    }

    @Override
    public boolean containsKey(Object key) {
        try (AutoCloseableLockWrapper autoCloseableLockWrapper = new AutoCloseableLockWrapper(readLock)) {
            autoCloseableLockWrapper.lock();
            return map.containsKey(key);
        }
    }
    ...
}

我不想在每个方法中创建包装器。

有没有办法结合单个包装器并尝试使用资源?

3 个答案:

答案 0 :(得分:1)

您可以使用返回单例的工厂方法。没有什么是强迫你使用构造函数。

顺便说一句,你不应该在try-block中调用lock。这应该已经发生在"获取资源"阶段(在当前设计的构造函数内,在我的提议中的工厂方法内)。

我看到上面的注释已经发布在Q&A page where you contributed your wrapper上了。该页面已经有很好的内容;我建议好好研究它。

答案 1 :(得分:1)

您的设计过于复杂。如果您的AutoCloseableLockWrapper故意公开基础Lock支持的所有操作,则无需为private添加Lock并为每个Lock方法添加委派方法。您可以简单地使public引用Lock允许其使用,或者完全不使用它,因为创建包装器的代码已经引用了unlock

您要做的只是支持单个操作AutoCloseable,该操作应被视为import java.util.concurrent.locks.Lock; public interface AutoUnlock extends AutoCloseable { public static AutoUnlock lock(Lock lock) { lock.lock(); return lock::unlock; } @Override public void close(); // no checked exceptions }

Java 8解决方案可能看起来像

Lock lock=…
// …
try(AutoUnlock u=AutoUnlock.lock(lock)) {
    // critical code
}
// …
try(AutoUnlock u=AutoUnlock.lock(lock)) {
    // critical code
}

可以像:

一样使用
AutoCloseable

如果您担心实例创建(通常这是问题),您可以重新使用AutoUnlock reusable=lock::unlock; // … lock.lock(); try(AutoUnlock u=reusable) { // critical code } // … lock.lock(); try(AutoUnlock u=reusable) { // critical code } s:

lock();

对我来说,它看起来不太清楚,因为tryfinal Lock lockInstance; // this field name is to prevent confusion with the lock() method final AutoUnlock reusable; YourConstructor(Lock lock) {// you may get the Lock as a parameter lockInstance=lock; // or create one here, right in the constructor reusable=lockInstance::unlock; } AutoUnlock lock() { lockInstance.lock(); return reusable; } void doSomething() { // … try(AutoUnlock u=lock()) { // critical code } // … try(AutoUnlock u=lock()) { // critical code } } 语句没有语法耦合,可能会意外分开。但是如果锁具有非局部范围,则可以通过创建实用程序方法来解决此问题:

with open('grades.txt') as f:
    print(Counter(f.read()))

我认为,如果需要,将此逻辑反向移植到Java 7代码中并不太难。

答案 2 :(得分:0)

我宁愿仅创建一个新锁(而不是围绕锁的包装器):

public class AutoReentrantLock implements AutoCloseable {
  private final ReentrantLock lock = new ReentrantLock();

  public AutoReentrantLock lock() {
    lock.lock();

    return this;
  }

  public void earlyUnlock() {
    lock.unlock();
  }

  @Override
  public void close() {
    if(lock.isHeldByCurrentThread()) {
      lock.unlock();
    }
  }
}

像这样使用:

private AutoReentrantLock consistencyLock = new AutoReentrantLock();

try(AutoReentrantLock lock = consistencyLock.lock()) {
  // other code
}

或更复杂的用例,您在其中途解锁:

private AutoReentrantLock consistencyLock = new AutoReentrantLock();

try(AutoReentrantLock lock = consistencyLock.lock()) {
  // Place code here that gathers information (while under lock)        
  // but may exit early or throw exceptions

  lock.earlyUnlock();

  // ... followed by code that is slow that acts upon above gathered information.
}