Locks AutoCloseable?

fre*_*low 42 java resources resource-management locks java-7

Locks AutoCloseable?也就是说,而不是:

Lock someLock = new ReentrantLock();
someLock.lock();
try
{
    // ...
}
finally
{
    someLock.unlock();
}
Run Code Online (Sandbox Code Playgroud)

我能说......么:

try (Lock someLock = new ReentrantLock())
{
    someLock.lock();
    // ...
}
Run Code Online (Sandbox Code Playgroud)

在Java 7中?

Ste*_*hen 53

我本人正在考虑自己这样做并做了类似这样的事情:

public class CloseableReentrantLock extends ReentrantLock implements AutoCloseable { 
   public CloseableReentrantLock open() { 
      this.lock();
      return this;
   }

   @Override
   public void close() {
      this.unlock();
   }
}
Run Code Online (Sandbox Code Playgroud)

然后这作为课程的用法:

public class MyClass {
   private final CloseableReentrantLock lock = new CloseableReentrantLock();

   public void myMethod() {
      try(CloseableReentrantLock closeableLock = lock.open()) {
         // locked stuff
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 我会考虑使锁本身不是AutoCloseable,而是让`open`返回一个单独的对象,其`close`释放锁.否则,你会冒险尝试`try(CloseableReentrantLock closeableLock = lock)`而没有`open`调用. (9认同)
  • 为此,该方法需要返回对象,但`lock()`继承自`ReentrantLock`并具有void返回类型.由于`lock()`在没有破坏继承的情况下是不可用的,`open()`与`close()`一起使用是有意义的. (3认同)
  • 这就是我目前正在做的事情,它使开发变得轻而易举。不能+1 就够了。 (2认同)
  • 因为覆盖是关闭的,所以打开/关闭比锁定/关闭更好(它们听起来像是在做同样的事情)。 (2认同)
  • 这是最好的解决方案,但是考虑到它仍然容易出错,我可能会在多个开发人员维护的大型代码库中坚持使用传统的(非资源尝试)方法。 (2认同)

dle*_*lev 23

不,Lock接口(也没有ReentrantLock类)都没有实现AutoCloseable接口,这是与新的try-with-resource语法一起使用所必需的.

如果你想让它工作,你可以编写一个简单的包装器:

public class LockWrapper implements AutoCloseable
{
    private final Lock _lock;
    public LockWrapper(Lock l) {
       this._lock = l;
    }

    public void lock() {
        this._lock.lock();
    }

    public void close() {
        this._lock.unlock();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以编写如下代码:

try (LockWrapper someLock = new LockWrapper(new ReentrantLock()))
{
    someLock.lock();
    // ...
}
Run Code Online (Sandbox Code Playgroud)

不过,我认为你最好坚持使用旧的语法.让锁定逻辑完全可见是更安全的.

  • 只是为初学者澄清一下:在实际代码中,每次锁定它时都不应该创建一个新锁,因为这会删除它的功能. (27认同)
  • +1我可能已经在构造函数中使用`lock()`了. (16认同)
  • 包装器未正确完成,将导致麻烦.只要问问自己:用旧方法,为什么`lock()`语句放在try块之外. (5认同)

sko*_*kav 8

通用ReentrantLock既不实现也不提供任何实现AutoCloseabletry-with-resources语句所必需的接口的东西.但是,这个概念对Java API来说并不完全陌生,因为它FileChannel.lock()提供了这个功能.

到目前为止给出的答案共享具有一些问题的解决方案,例如在每次锁定调用上创建不必要的对象,暴露容易出错的API或在获取锁定之后但在输入try-finally之前风险失败.

Java 7解决方案:

public interface ResourceLock extends AutoCloseable {

    /**
     * Unlocking doesn't throw any checked exception.
     */
    @Override
    void close();
}

public class CloseableReentrantLock extends ReentrantLock {

    private final ResourceLock unlocker = new ResourceLock() {
        @Override
        public void close() {
            CloseableReentrantLock.this.unlock();
        }
    };

    /**
     * @return an {@link AutoCloseable} once the lock has been acquired.
     */
    public ResourceLock lockAsResource() {
        lock();
        return unlocker;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用lambda的Leaner Java 8解决方案:

public class CloseableReentrantLock extends ReentrantLock {

    /**
     * @return an {@link AutoCloseable} once the lock has been acquired.
     */
    public ResourceLock lockAsResource() {
        lock();
        return this::unlock;
    }
}
Run Code Online (Sandbox Code Playgroud)

示范:

public static void main(String[] args) {
    CloseableReentrantLock lock = new CloseableReentrantLock();

    try (ResourceLock ignored = lock.lockAsResource()) {
        try (ResourceLock ignored2 = lock.lockAsResource()) {
            System.out.println(lock.getHoldCount());  // 2
        }
    }
    System.out.println(lock.getHoldCount());  // 0
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎没有回答有关Java 7和AutoCloseable的问题.你的意思是这是一个单独的问题吗? (3认同)
  • 您的Java 8解决方案非常优雅。做得好!我已经在/sf/answers/3370168861/上发布了“ ReadWriteLock”的相关设计。 (2认同)

Edu*_*rch 5

try-with-resource为其创建和销毁时的资源运作良好try-block的离开了。它对于需要保持活动状态的资源不起作用。不会在每次使用时创建和销毁锁。它们保持活动状态,只是被锁定和解锁。这就是为什么它们不是这样AutoClosable

正如其他人已经建议的那样,可以使用包装器来创建和销毁包装,try-with-resource并在创建和销毁时进行锁定和解锁。