Another Java Singleton Problem

See also JavaSingletonProblems for a list of problems related to Singletons in Java, and JavaSingleton and other JavaPatterns.


I have recently started designing a Java applet which uses several singleton objects. The applet is going to be used as part of an online assessment system, so there is a distinct possibility that more than one applet will appear on a single page of HTML.

This started me thinking about how the singleton pattern would behave. My concern is that a particular browser could run both applets in the same NameSpace, causing both to share instances of the various singleton objects.

Also, the same thing would happen in a multi-threaded, multi-user environment. This may sound daft in connection with a single VM, but I'm thinking about servlets here, which kick off server responses in separate threads. Some singleton objects would be system wide, but others, such as command history objects, would be context sensitive.

My solution is to provide key-based access to particular instantiations of singleton objects. Rather than storing a static reference to the current instance, the singleton class can implement a hash table. Clients requesting the singleton object would have to provide a key. The key becomes a marker for a particular context.

I have the feeling that this is only the start of a solution, because the key may have to be passed around a distributed system, and possibly "pickled" inbetween transactions.

Hmm, I suppose I could also use a FacadePattern to gather together all of the context sensitive objects, rather than making them singletons.

Any comments? related problems? Or am I worrying over nothing here...

-- DavidMcNicol


This is a definite problem, but you can solve it easily through knowledge of how browsers determine their name spaces. Unfortunately, I haven't found this documented anywhere, so I had to do a bit of experimentation (using IE, Navigator, and HotJava).

Applets will only share NameSpaces if both their document paths and their applet paths are identical. This means that you can have two applets use the same real code base, but not share NameSpaces if their home pages are in different directories.

For example, use the following directory structure:

root

  +---- code
  +---- applet1
  +---- applet2
and have both applet1 and applet2 launched from an APPLET tag with the following CODEBASE tag:

CODEBASE=../code

This makes the applets different enough to guarantee that statics are not shared.

-- RussellGold

Each ClassLoader has a separate NameSpace. If your applet can instantiate a ClassLoader and load its classes from that, you can guarantee that your singletons will not interfere with those of other applets.

Conversely, there is no way to guarantee that there is only one instance of a Singleton class in a JVM because the same class might be loaded by different ClassLoaders? and so instantiated more than once.

-- NatPryce

If possible in any way, I would do without singletons. Why not just keep the unique instance of whatever in your Applet subclass? This also ensures that the singleton can be garbage collected when the Applet exits.

-- ThomasMaeder

I ended up sorting this problem from a different angle, by considering these shared objects as resources, and grouping them together into a "resource context" object. The code passes the resource context object around to any other objects that need to access the resources. All of the passing around is done inside factory objects (usually by calling setResourceContext() just after a new object is instantiated).

-- DavidMcNicol

Yup! HaveThisPattern.

-- ThomasMaeder

Ah! I found this discussion six months too late, but I HaveThisPattern too.

One little-known feature that can help a lot (it was introduced into 1.2 with no fanfare) is the InheritableThreadLocal? class. It permits having singleton-like resources (accessible from anywhere without passing them around) but you can control which particular instance of a resource is accessible to a particular thread, and new threads inherit the resource from the creating thread. -- GlennVanderburg

When using servlets, you should also make sure you understand the role of the Session. Many of your singletons might live in the session (which is similar to implementation described at the top) which if used correctly will isolate one user from another. As a session is cookie based however, multiple connections from the same machine to the same domain will share the same session (which might still be a problem from what you describe). -- TimMackinnon

I think that this is actually an example of an AntiPattern. Let's call it MostlyGlobalVariable?. Singletons should not be used to provide execution context; you should implement some kind of call-stack context mechanism if that's what you need. Otherwise, how are you going to unit test interactions between multiple different execution contexts operating at once? The SingletonPattern is for instances which you really only need *one* of, for ever and ever, amen. If you want "one per process" or "one per applet", figure out a convenient way to get to a reified version of the process or applet as an object, and then use attributes of that. (The object which _manages_ such execution context is probably a singleton, and has a method like 'getCurrent()' rather than 'getInstance()'.) -- GlyphLefkowitz


several singleton objects

Does anyone else think there is something wrong about that notion?

Back to the question: Obviously you aren't looking at singletons. You are misapplying and possibly misunderstanding the singleton pattern; but don't worry, singletons have a tendency to do that to people. In your case, why don't you just create the stupid objects in main() or appletInit() and pass them around? That's cleaner in the end.


CategoryJava


EditText of this page (last edited August 8, 2007) or FindPage with title or text search