java 锁可以自动关闭吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6965731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 18:03:38  来源:igfitidea点击:

Are Locks AutoCloseable?

javaresourcesjava-7resource-managementlocks

提问by fredoverflow

Are Locksauto-closeable? That is, instead of:

可以Locks自动关闭吗?也就是说,而不是:

Lock someLock = new ReentrantLock();
someLock.lock();
try
{
    // ...
}
finally
{
    someLock.unlock();
}

...can I say:

...我能说......么:

try (Lock someLock = new ReentrantLock())
{
    someLock.lock();
    // ...
}

...in Java 7?

...在 Java 7 中?

采纳答案by dlev

No, neither the Lockinterface (nor the ReentrantLockclass) implement the AutoCloseableinterface, which is required for use with the new try-with-resource syntax.

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

If you wanted to get this to work, you could write a simple wrapper:

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

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

Now you can write code like this:

现在你可以写这样的代码:

try (LockWrapper someLock = new LockWrapper(new ReentrantLock()))
{
    someLock.lock();
    // ...
}

I think you're better off sticking with the old syntax, though. It's safer to have your locking logic fully visible.

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

回答by Stephen

I was looking into doing this myself and did something like this:

我正在考虑自己做这件事并做了这样的事情:

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

   @Override
   public void close() {
      this.unlock();
   }
}

and then this as usage for the class:

然后这是该课程的用法:

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

   public void myMethod() {
      try(CloseableReentrantLock closeableLock = lock.open()) {
         // locked stuff
      }
   }
}

回答by skoskav

The general-purpose ReentrantLockneither implements nor provides anything that implements the AutoCloseableinterface necessary for a try-with-resources statement. The concept isn't completely foreign to the Java API though, as FileChannel.lock()offers this functionality.

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

The answers given so far share solutions that have some issues, such as creating an unnecessary object on each lock call, exposing an error-prone API or risk failing after the lock is acquired but before the try-finally is entered.

到目前为止给出的答案分享了存在一些问题的解决方案,例如在每次锁定调用时创建一个不必要的对象、暴露容易出错的 API 或在获取锁定之后但在进入 try-finally 之前失败的风险。

Java 7solution:

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

Leaner Java 8solution using a lambda:

使用 lambda 的精简Java 8解决方案:

public class CloseableReentrantLock extends ReentrantLock {

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

Demonstration:

示范:

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
}

回答by Eduard Wirch

The try-with-resourceworks well for resources which are created and destroyed when try-blockis left. It does not work for resources which need to be kept alive. Locks are not created and destroyed upon each usage. They are kept alive and just locked and unlocked. This is why they are not AutoClosable.

try-with-resource适用于在try-block剩余时创建和销毁的资源。它不适用于需要保持活动状态的资源。不会在每次使用时创建和销毁锁。它们保持活动状态,只是锁定和解锁。这就是为什么他们不是AutoClosable

As others already suggested a wrapper can be used to be created and destroyed by the try-with-resourceblock and to do the locking and unlocking upon creation and destruction.

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

回答by maaartinus

There's no perfect solution, unless you ignore the allocation costs (most application programmers can, but the lock library writers can not). Then you can use a wrapper

没有完美的解决方案,除非您忽略分配成本(大多数应用程序程序员可以,但锁库编写者不能)。然后你可以使用包装器

@RequiredArgsConstructor(access=AccessLevel.PRIVATE)
public final class MgLockCloseable implements AutoCloseable {
    public static MgLockCloseable tryLock(Lock lock) {
        return new MgLockCloseable(lock.tryLock() ? lock : null);
    }

    public static MgLockCloseable lock(Lock lock) {
        lock.lock();
        return new MgLockCloseable(lock);
    }

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

    public boolean isLocked() {
        return lock != null;
    }

    @Nullable private final Lock lock;
}

in this construct

在这个构造中

try (LockCloseable lockCloseable = LockCloseable.lock(lock)) {
    doSomethingUnderLock();
} // automatic release

See also my question on CR.

另请参阅我关于 CR 的问题

回答by sp00m

Taking user2357112's shrewd adviceinto account:

考虑到user2357112 的精明建议

public class CloseableLock {

  private class Unlocker implements AutoCloseable {

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

  }

  private final Lock lock;

  private final Unlocker unlocker = new Unlocker();

  public CloseableLock(Lock lock) {
    this.lock = lock;
  }

  public AutoCloseable lock() {
    this.lock.lock();
    return unlocker;
  }

}

Use:

利用:

CloseableLock lock = new CloseableLock(new ReentrantLock());

try (AutoCloseable unlocker = lock.lock()) {
    // lock is acquired, automatically released at the end of this block
} catch (Exception it) {
    // deal with it
}

Could be interesting to make CloseableLockimplement java.util.concurrent.locks.Lock.

制作CloseableLock工具可能很有趣java.util.concurrent.locks.Lock

回答by ocroquette

Building on Stephen's answer and user2357112's idea, I have written the following class.

基于斯蒂芬的回答和 user2357112 的想法,我编写了以下课程。

The MyLock class itself is not closeable itself, to force users of the class to call get().

MyLock 类本身不可关闭,以强制该类的用户调用 get()。

public class MyLock  {
    public class Session implements AutoCloseable {
        @Override
        public void close() {
            freeLock();
        }
    }

    private ReentrantLock reentrantLock = new ReentrantLock();

    public Session get() { 
        reentrantLock.lock();
        return new Session();
    }

    private void freeLock() {
        reentrantLock.unlock();
    }
}

Here is a typical use:

这是一个典型的用途:

MyLock myLock = new MyLock();
try( MyLock.Session session = myLock.get() ) {
    // Lock acquired
}

回答by SomeUsername1

Extending the Java8 solution of @skoskav to ReentrantReadWriteLock:

将@skoskav的Java8方案扩展为ReentrantReadWriteLock:

public interface ResourceLock extends AutoCloseable {
    /**
     * Unlocking doesn't throw any checked exception.
     */
    @Override
    void close();
}    
public class CloseableReentrantRWLock extends ReentrantReadWriteLock {

    /**
     * @return an {@link AutoCloseable} once the ReadLock has been acquired
     */
    public ResourceLock lockRead() {
        this.readLock().lock();
        return () -> this.readLock().unlock();
    }

     /**
     * @return an {@link AutoCloseable} once the WriteLock has been acquired.
     */
    public ResourceLock lockWrite() {
        this.writeLock().lock();
        return () -> this.writeLock().unlock();
    }
} 

回答by Lii

I think a simple util method which takes a lock and a Runnableis better than using the try-with-resource statement with locks.

我认为采用锁和 a 的简单 util 方法Runnable比使用带锁的 try-with-resource 语句更好。

Like this:

像这样:

public static void locked(Lock lock, Runnable r) {
    lock.lock();

    try {
        r.run();
    } finally {
        lock.unlock();
    }
}

Usage example:

用法示例:

locked(lock, () -> {
    // Do your stuff
});

Advantages:

好处:

  • There is no dummy variable created for the try-with-resource.
  • I think it is very clear.
  • 没有为 try-with-resource 创建虚拟变量。
  • 我认为这是非常清楚的。

Disadvantage

坏处

  • A Runnableinstance is allocated for each calls, something that some of the other solutions avoid. But this is insignificant in almost all cases.
  • Only works if you can use Java 8.
  • Runnable为每个调用分配一个实例,这是其他一些解决方案避免的。但这在几乎所有情况下都是微不足道的。
  • 仅当您可以使用 Java 8 时才有效。

回答by gstackoverflow

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