Java Programming Tip: Keyed Singletons
Most Java programmers are familiar with the "singleton" pattern, shown in this snippet:
public class MyService { static private MyService INSTANCE = null; static public MyService getInstance() {
if( INSTANCE == null ) {
INSTANCE = new MyService();
} return INSTANCE;
} private MyService() {
}
} However, I've found that sometimes in a complex application, it can be useful to have instances of particular classes that act like singletons, but only in terms of a specific context. For example, perhaps you are working on an application that allows you to edit "projects" of some sort, and within the scope of each project you only want exactly one instance of a particular service, such as an "Undo Manager" or a "History Manager". You want it to work like a utility class, but it needs to maintain state that is specific to the context in which it's being used.
public class MyService { static private final Map<Object,MyService> INSTANCES = new HashMap<Object,MyService>(); static public MyService getInstance(Object key) {
MyService service = null; if( INSTANCES.get(key) == null ) {
service = new MyService();
INSTANCES.put(key, service);
} return service;
} private MyService() {
} }
In the above example, instances are lazily initialized just like you'd expect from a singleton implementation, but then they're added to a
Map which tracks every instance based on the key it was created with. One will quickly notice that there's a problem with using this approach in some cases, though, which is that there's no obvious removal semantic. In other words, you'll quickly end up with a lot of instances in your Map and no way to get rid of them. Also, if you are using large objects (such as some kind of Project class) as your keys, then you could be creating a rather severe memory leak. You could add a removal method, but I have a better way! Just substitute in this line:
static private final Map<Object,MyService> INSTANCES = new WeakHashMap<Object,MyService>();
Instantly you have now made all of the references to your keys into "weak references," meaning the
Map itself cannot prevent garbage collection of the key instances. Better yet, when one of the keys is garbage collected, its associated value entry is removed from the Map as well. In this way, careful use of a keyed singleton pattern can provide a scoped, self-cleaning service management framework.


