MySQL has a handy function:
SELECT GET_LOCK("SomeName")
This can be used to create simple, but very specific, name based locks for an application. However, it requires a database connection.
I have many situations like:
someMethod() {
// do stuff to user A for their data for feature X
}
It doesn't make sense to simply synchronize this method, because, for example, if this method is called for user B in the meantime, user B does not need to wait for user A to finish before it starts, only operations for the user A and feature X combination need to wait.
With the MySql lock I could do something like:
someMethod() {
executeQuery("SELECT GET_LOCK('userA-featureX')")
// only locked for user A for their data for feature X
executeQuery("SELECT RELEASE_LOCK('userA-featureX')")
}
Since Java locking is based on objects, it seems like I would need to create a new object to represent the situation for this lock and then put it in a static cache somewhere so all the threads can see it. Subsequent requests to lock for that situation would then locate the lock object in the cache and acquire its lock. I tried to create something like this, but then the lock cache itself needs synchronization. Also, it is difficult to detect when a lock object is no longer being used so that it can be removed from the cache.
I have looked at the Java concurrent packages, but nothing stands out as being able to handle something like this. Is there an easy way to implement this, or am I looking at this from the wrong perspective?
Edit:
To clarify, I am not looking to create a predefined pool of locks ahead of time, I would like to create them on demand. Some pseudo code for what I am thinking is:
LockManager.acquireLock(String name) {
Lock lock;
synchronized (map) {
lock = map.get(name);
// doesn't exist yet - create and store
if(lock == null) {
lock = new Lock();
map.put(name, lock);
}
}
lock.lock();
}
LockManager.releaseLock(String name) {
// unlock
// if this was the last hold on the lock, remove it from the cache
}
After some disappointment that there is no language level support or simple Guava/Commons class for named locks,
This is what I settled down to:
Here I achieved: little boilerplate code with no library dependency, atomically acquiring the lock object, not polluting the global interned string objects, no low-level notify/wait chaos and no try-catch-finally mess.
Here is a simple and optimized solution which addresses the removal of used locks also, but with an overhead of synchronization of the Map:
}
All those answers I see are way too complicated. Why not simply use:
The key point is the method
intern
: it ensures that the String returned is a global unique object, and so it can be used as a vm-instance-wide mutex. All interned Strings are held in a global pool, so that's your static cache you were talking about in your original question. Don't worry about memleaks; those strings will be gc'ed if no other thread references it. Note however, that up to and including Java6 this pool is kept in PermGen space instead of the heap, so you might have to increase it.There's a problem though if some other code in your vm locks on the same string for completely different reasons, but a) this is very unlikely, and b) you can get around it by introducing namespaces, e.g.
executeInNamedLock(this.getClass().getName() + "_" + myLockName);
Your idea about a shared static repository of lock objects for each situation is correct.
You don't need the cache itself to be synchronized ... it can be as simple as a hash map.
Threads can simultaneously get a lock object from the map. The actual synchronization logic should be encapsulated within each such object separately (see the java.util.concurrent package for that - http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/package-summary.html)
This thread is old, but a possible solution is the framework https://github.com/brandaof/named-lock.
Maybe a little later but you can use Google Guava Striped