Consider I have a number of string values (dynamically generated), and a thread pool, and I want each string value to be exclusively owned by at most a single thread at any time. So, for instance, if the string "foo" is locked by a thread T1 at some period in time, all other threads waiting to process "foo" (or any other string equal to "foo" in terms of Object.equals()
) must wait until thread T1 releases the lock.
So I want to implement the following interface:
interface Lock {
void lock(@NonNull String key);
void unlock(@NonNull String key);
}
As I said, any thread entering the lock(String)
method should wait (or wait interruptibly, or wait with a time-out) if the key is already locked by some other thread.
And the unlock(String)
method should effectively unlock the key, throwing an exception in two cases:
Apparently, when implementing the above interface, I have to associate a ReentrantLock
instance with any key that is about to get locked, for the whole time it remains locked.
How do I implement the LockByKey
interface? Which concurrency primitives from the java.util.concurrent
package are most suitable for this task?
You need something like this
public class StringLockImpl implements StringLock {
private final Map<String, LockObject> map = new HashMap<>();
private final Lock lock = new ReentrantLock();
@Override
public void lock(String key) {
acquire(key).lock();
}
@Override
public void unlock(String key) {
release(key).unlock();
}
private Lock acquire(String key) {
lock.lock();
try {
LockObject lockObject = map.computeIfAbsent(key, ignore -> new LockObject());
lockObject.inc();
return lockObject.getLock();
} finally {
lock.unlock();
}
}
private Lock release(String key) {
lock.lock();
try {
LockObject lockObject = map.get(key);
if (lockObject.dec()) {
map.remove(key);
}
return lockObject.getLock();
} finally {
lock.unlock();
}
}
private static class LockObject {
private int counter;
@Getter
private final Lock lock = new ReentrantLock();
public void inc() {
counter++;
}
public boolean dec() {
return --counter == 0;
}
}
}
If you search the net, you probably find existing implementation.