What is the best way to prevent concurrent update of one record in a key-value set without locking the entire set? Semantically, I'm looking for some kind of locking by a key (ideally, Java implementation, but not necessarily):
interface LockByKey { void lock(String key); // acquire an exclusive lock for a key void unlock(String key); // release lock for a key }
This lock is intended to synchronize an access to a remote store, so some synchronized Java collection is not an option.
Yes, an experienced locksmith should generally have the ability to make a lock from a key. However, it is important to remember that the steps involved in this process can be challenging for even experienced locksmiths and may require some patience on the part of the client or customer.
Acquiring a lock allows a thread to have exclusive access to the data guarded by that lock, forcing other threads to block — as long as those threads are also trying to acquire that same lock. The monitor pattern guards the rep of a datatype with a single lock that is acquired by every method.
class as a parameter tells which class has to synchronized at the class level. As soon as the thread entered the synchronized block, the thread acquire the lock at class, rest of the threads wait to get the class monitor lock. The thread will leave lock when it exits from the synchronized block.
If it's a lost key a locksmith can make you a key without the original, as locksmiths can make keys to lock by hand. By using a blank and a file and the skills, they've developed over the years a locksmith can create a key from scratch without the need for an original key.
Guava has something like this being released in 13.0; you can get it out of HEAD if you like.
Striped<Lock>
more or less allocates a specific number of locks, and then assigns strings to locks based on their hash code. The API looks more or less like
Striped<Lock> locks = Striped.lock(stripes); Lock l = locks.get(string); l.lock(); try { // do stuff } finally { l.unlock(); }
More or less, the controllable number of stripes lets you trade concurrency against memory usage, because allocating a full lock for each string key can get expensive; essentially, you only get lock contention when you get hash collisions, which are (predictably) rare.
(Disclosure: I contribute to Guava.)
private static final Set<String> lockedKeys = new HashSet<>(); private void lock(String key) throws InterruptedException { synchronized (lockedKeys) { while (!lockedKeys.add(key)) { lockedKeys.wait(); } } } private void unlock(String key) { synchronized (lockedKeys) { lockedKeys.remove(key); lockedKeys.notifyAll(); } } public void doSynchronously(String key) throws InterruptedException { try { lock(key); //Do what you need with your key. //For different keys this part is executed in parallel. //For equal keys this part is executed synchronously. } finally { unlock(key); } }
try-finally - is very important - you must guarantee to unlock waiting threads after your operation even if your operation threw exception.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With