Package net.dapete.locks
This package contains classes for key-based locking, as in a way to obtain instances of Lock
or ReadWriteLock
which are identified by a key. These locks are guaranteed to by different for each key and
will be kept as long as they are referenced.
Type of Lock | Method(s) | Type returned |
---|---|---|
ReentrantLock |
Locks.reentrant() Locks.reentrant(Class) Locks.reentrant(boolean) Locks.reentrant(boolean, Class) |
ReentrantLocks |
any implementation of Lock |
Locks.withSupplier(Supplier) |
Locks |
ReentrantReadWriteLock |
ReadWriteLocks.reentrant() ReadWriteLocks.reentrant(Class) ReadWriteLocks.reentrant(boolean) ReadWriteLocks.reentrant(boolean, Class) |
ReentrantReadWriteLocks |
any implementation of ReadWriteLock |
ReadWriteLocks.withSupplier(Supplier) |
ReadWriteLocks |
-
All implementations use generics for the type of the key as well as the type of lock, if this is not fixed (as with
ReentrantLocks
andReentrantReadWriteLocks
). -
The
Class
parameter on thereentrant(Class)
andreentrant(boolean, Class)
methods is theClass
of the key type. This is a shortcut for readability if the compiler does not automatically detect it, for example:
Locks.reentrant(String.class)
-
The
boolean
parameter on thereentrant(boolean)
andreentrant(boolean, Class)
sets the fairness policy of the reentrant lock instances used. See also the constructorsReentrantLock(boolean)
andReentrantReadWriteLock(boolean)
. -
The
withSupplier(Supplier)
methods allow for any implementation ofLock
orReadWriteLock
to be used. Just use the constructor as theSupplier
, for example:
Locks.withSupplier(SuperEpicLock::new)
Examples
Following the same pattern as described in the JDK documentation for Lock
, using Locks
should look similar to this:
public class LocksExample {
private final ReentrantLocks<String> locks = Locks.reentrant();
public void doSomething(String url) {
final var lock = locks.lock(url);
try {
// do something with the URL
} finally {
lock.unlock();
}
}
}
It is important to keep the lock in a local variable while it is being used. It is stored in a WeakReference
, so it
could be removed by the garbage collector at any time while it is not referenced.
An alternative way which may be useful if the lock is not always used or used multiple times would be to split the final var lock = …
line
in two:
final var lock = locks.get(url);
lock.lock();
For ReadWriteLocks
it is similar to the first example:
public class ReadWriteLocksExample {
private final ReentrantReadWriteLocks<String> locks = ReadWriteLocks.reentrant();
public void doSomethingRead(String url) {
final var lock = locks.readLock(url);
try {
// do something with the URL
} finally {
lock.readLock().unlock();
}
}
public void doSomethingWrite(String url) {
final var lock = locks.writeLock(url);
try {
// do something with the URL
} finally {
lock.writeLock().unlock();
}
}
}
Again the final var lock = …
lines could be split, which may be useful if both read and write locks are used in the method.
-
ClassDescriptionKey-based locking with implementations of
Lock
.ReadWriteLocks<K,L extends ReadWriteLock> Key-based locking with implementations ofReadWriteLock
.Key-based locking using instances ofReentrantLock
.Key-based locking using instances ofReentrantReadWriteLock
.