Are Locks AutoCloseable?

2019-01-18 01:35发布

Are Locks AutoCloseable? That is, instead of:

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

can I say:

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

in Java 7?

8条回答
我只想做你的唯一
2楼-- · 2019-01-18 02:05

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

The MyLock class itself is not closeable itself, to force users of the class to call 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
}
查看更多
Lonely孤独者°
3楼-- · 2019-01-18 02:06
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();
    }
}
查看更多
男人必须洒脱
4楼-- · 2019-01-18 02:07

No, neither the Lock interface (nor the ReentrantLock class) implement the AutoCloseable interface, which is required for use with the new try-with-resource syntax.

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.

查看更多
再贱就再见
5楼-- · 2019-01-18 02:10

Taking user2357112's shrewd advice into account:

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 CloseableLock implement java.util.concurrent.locks.Lock.

查看更多
Bombasti
6楼-- · 2019-01-18 02:12

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
      }
   }
}
查看更多
Juvenile、少年°
7楼-- · 2019-01-18 02:16

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.

查看更多
登录 后发表回答