Универсальное ReentrantLock
не реализует и не предоставляет ничего, что реализует интерфейс AutoCloseable
, необходимый для оператора try-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;
}
}
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;
}
}
Демонстрация:
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
}