universales una tener seguridad puertas para paleta original mercadolibre maestra llaves llave hacer doble copia como cerraduras casa candados java resources java-7 resource-management locks

java - una - ¿Las cerraduras se pueden cerrar automáticamente?



llave maestra mercadolibre (8)

¿Son las cerraduras auto-reutilizables? Es decir, en lugar de:

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

Puedo decir:

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

en java 7?


El ReentrantLock propósito ReentrantLock no implementa ni proporciona nada que implemente la interfaz AutoCloseable necesaria para una declaración try-with-resources. Sin embargo, el concepto no es completamente ajeno a la API de Java, ya que FileChannel.lock() ofrece esta funcionalidad.

Las respuestas proporcionadas hasta ahora comparten soluciones que tienen algunos problemas, como crear un objeto innecesario en cada llamada de bloqueo, exponer una API propensa a errores o arriesgarse a fallar después de que se adquiere el bloqueo pero antes de que se ingrese en try-finally.

Solución de 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; } }

Solución Java 8 más fina utilizando un lambda:

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

Demostración:

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 }


El try-with-resource funciona bien para los recursos que se crean y destruyen cuando se deja try-block . No funciona para los recursos que necesitan mantenerse vivos. Los bloqueos no se crean y se destruyen con cada uso. Se mantienen vivos y simplemente bloqueados y desbloqueados. Es por esto que no son AutoClosable .

Como otros ya han sugerido try-with-resource bloque try-with-resource puede usar y envolver una envoltura y hacer el bloqueo y desbloqueo en la creación y destrucción.


Estaba buscando hacer esto yo mismo e hice algo como esto:

public class CloseableReentrantLock extends ReentrantLock implements AutoCloseable { public CloseableReentrantLock open() { this.lock(); return this; } @Override public void close() { this.unlock(); } }

y luego esto como uso para la clase:

public class MyClass { private final CloseableReentrantLock lock = new CloseableReentrantLock(); public void myMethod() { try(CloseableReentrantLock closeableLock = lock.open()) { // locked stuff } } }


No hay una solución perfecta, a menos que ignore los costos de asignación (la mayoría de los programadores de aplicaciones pueden, pero los escritores de la biblioteca de bloqueo no pueden). Entonces puedes usar una envoltura

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

en este constructo

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

Véase también mi pregunta sobre CR .


No, ni la interfaz Lock (ni la clase ReentrantLock ) implementan la interfaz AutoCloseable , que se requiere para usar con la nueva sintaxis try-with-resource.

Si quisiera que esto funcionara, podría escribir un envoltorio simple:

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

Ahora puedes escribir código como este:

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

Sin embargo, creo que es mejor que te quedes con la sintaxis antigua. Es más seguro tener su lógica de bloqueo completamente visible.


Sobre la base de la respuesta de Stephen y la idea de user2357112, he escrito la siguiente clase.

La clase MyLock en sí no se puede cerrar por sí misma, para obligar a los usuarios de la clase a llamar a 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(); } }

Aquí es un uso típico:

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


Teniendo en cuenta el astuto consejo de 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; } }

Utilizar:

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 }

Podría ser interesante hacer que CloseableLock implemente java.util.concurrent.locks.Lock .


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