1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Manages a set of mutexes unique in this context.
*
* <p>As mentionned in section 3.10.5 of the Java Language Spec 2.0,
* "Literal strings within different classes in different packages
* likewise represent references to the same String object."<br/>
* This class allow to create a context in order to manage safe
* string-based mutexes, that is to say without the inherent
* conditions of the String class that can lead to a dead-lock.</p>
*
* <p>This class is not magic:<p>
* <ul>
* <li>It's up to the user to create a context per domain to avoid
* ID collisions. The scope of such domain depends on the application.</li>
* <li>It can't avoid dead-lock due to programming (it only avoids
* the inherent possibility of dead-locks due to string usage)</li>
* </ul>
*
* <p>A mutex doesn't have to be explicitly remove from this context,
* it will be automatically removed after all references to it are
* dropped.</p>
*
* @see Mutex
*/
public class MutexContext {
// based on http://illegalargumentexception.blogspot.com/2008/04/java-synchronizing-on-transient-id.html
private final Map<Mutex, WeakReference<Mutex>> mutexMap = new WeakHashMap<Mutex, WeakReference<Mutex>>();
/**
* Return a lockable mutex.
*
* @param id The string ID.
*
* @return A synchronizable object, unique in this context.
*/
public Mutex getMutex(String id) {
Mutex key = new Mutex(id);
synchronized(mutexMap) {
WeakReference<Mutex> ref = this.mutexMap.get(key);
if (ref==null) {
this.mutexMap.put(key, new WeakReference<Mutex>(key));
return key;
}
Mutex mutex = ref.get();
if (mutex==null) {
this.mutexMap.put(key, new WeakReference<Mutex>(key));
return key;
}
return mutex;
}
}
} |
Partager