Singletonitis

Do you suffer from singleton-itis? That may be bad for your code's health...

Singletonitis defined

Singletonitis is a disease that makes you use lots of singletons in your code, even when you don't need them.

A variation of singletonitis is "static-itis", that produces lots of static methods in your code.

Singletonitis is a difficult to detect disease. You happen to suffer from it and you don't really appreciate the symptoms. Until it's too late and your soul is completely sold. You're trapped by this disease, and there's little you can do to arrange it.

Let's review some of the dysfunctions that singletonitis may cause and, later on, let's review some of the possible cures.

Why singletons may be bad: because they're not unique!

Well, in case you didn't know, even double-checked locking is flawed so implementing a singleton in Java is somewhat tricky.

Warning: Remember that you have a unique instance of singletons per classloader

It's easier than in C++, of course. Scott Meyers has been explaining how to do singletons in C++ for quite a long time (well, before Java was invented, I think. Note that he has not changed the photo in his web page for ten years ;-))

But double-checked locking is not the only problem. If you solve that you may still have different singletons.

Singletons in J2EE environments

If you have used singletons in web applications you may have noticed that singletons may not be unique. This usually happens because web applications in J2EE environments may use different, separate, classloaders.

Classloaders are responsible for loading classes, so a singleton instance is unique per classloader (or per classloader hierarchy). If your J2EE application server uses different, separate, classloaders then you're in trouble. You may think there's a single singleton, but there're more.

The solution for this symptom is to move the singleton class to a classloader that loads classes in different tiers: a common classloader, that turns usually to be the application-server classloader. The one you have to specify in the command line of the application server. The one that requires you to restart the application server for the classes to be reloaded.

Why singletons may be bad: because there's only one!

Another dysfunction of singletonitis is that when you use a singleton there's a single instance (well, except in the cases that fit the previous category).

And having a single instance of anything may be, indeed, very bad for your code's health.

Because you may want to share that instance between different threads. And, well, is that instance synchronized?

Using ThreadLocal? Warning: You may be suffering singletonitis!

This is a painful situation: you build something with a single instance, with a singleton, and you suddenly realize you're using that from different threads! That's terrifying!

That's what I think has happened with Spring and Hibernate. Hibernate Sessions are not singletons (well, of course) and you're probably supposed to use one session per thread. Spring, on the contrary, may share code between threads (because it makes heavy use of singletons).

So Spring and Hibernate just don't mix

One of the symptoms of this dysfunction of singletonitis is the "apparition" of ThreadLocals in your code. People tend to use ThreadLocals to solve the problem, so you may end up writing code like this:

public class ItemDAO {

    Session currentSession;

    public ItemDAO() {
        currentSession = HibernateUtil.getSessionFactory().getCurrentSession();
    }

    public Item getItemById(Long itemId) {
        return (Item) currentSession.load(Item.class, itemId);
    }
}

But, well, note that ThreadLocal stuff does not always work, so it may happen that you end up manually refactoring all your code. And that's painful too.

By the way, don't ever never handle transactions in J2EE servlet filters: that's asking for trouble (and it's not very solid). What happens if the user closes the web browser in-between a transaction? A solid J2EE application may rollback the ongoing transaction (in the EJB tier), a solution with servlet filters may (or may not) rollback that transaction.

Why singletons may be bad: coupling

One of the worst effects of using singletons is coupling. Coupling between different parts of an application that should not be coupled.

You can surely live with this dysfunction without too many problems, even during months of development.

Until you realize about the problem (usually too late) and the cure is, well, painful.

Warning: singletons may produce high coupling! (this is, lots of headaches and long working hours at night)

Let's see this with an example. Imagine you're building a web application and that you use a singleton both from the servlets and the ejbs. That's ok. You deploy your application to an application server, and you realize you need to separate the servlets and the ejbs because of scalability concerns. You want to deploy the servlets in two application servers, and the ejbs (that have much more workload) in ten application servers.

What happens with that singleton then? Where're you going to place it? Can you split it in two different singletons? Possibly not, because you can use it to pass information (global state) between the two different tiers.

The solution happens to be a refactoring of your code. Well, not exactly. A refactoring may be done automatically. You'll have to review your code by hand, manually separating the coupling between the web (servlets) tier and the ejb (business) tier.

And, well, that's a lot of pain.

(By the way, I don't get Spring, either although I admit I've not used it yet (I'm a lucky one! ;-). I don't really like using too many singletons (Spring uses lots of them). I prefer writing EJB deployment descriptors than Spring XML documents (NetBeans builds them for me automagically). After all, I could suffer from... singletonitis!

Why singletons may be bad: unit testing

Warning: Singletons may be bad for your unit testing

Well, of course! The objective of unit testing is to unit test each single class independently, right? Now, if your class is suffering singletonitis then you'll have to test both your class and your singleton, right?

Because there's a coupling between your class and your singleton.

And that's bad for unit testing.

For further reading on the problems of unit testing with singletons please see this excellent entry at IBM Developerworks.

Why singletons may be bad: because they cannot be changed

Singletons are not polymorphic. (Although someone has implemented some sort of workaround).

But the problem is changing them. Once in production. Because you have a big coupling. Adding a parameter to a single method may be a real pain.

Recipes against singletonitis

Well, the first and most important recipe for curing your singletonitis is not to use singletons at all.

I know singletons are handy. I use them too. But I think I shouldn't. Let's see some Swing examples.

Resisting the temptation: Scott's Application class

Remember Scott Violet's blog entry about the Application class? Well, at first glance I was tempted to make the Application class a singleton.

That would be handy. In fact some of the comments in his blog talk about having a singleton application instance, so that the Application can be instantiated only once.

But, why so? Scott admits it in his blog, as well.

Just one thought: using static field in the abstract Application class to ensure the application is a singleton forbids instanciations of multiple implementations in the same context (say, an application launcher that launches other apps). You are certainly correct.

Yep. He is correct. Singletons won't do here.

Because it's true that you may want to have things share that application class. Using singletons for that class limit your possibilities. It's much easier to have different Application instances, and pass them only to appropiate parts of the application. Otherwise you'll end up with a high coupled architecture. And then you're in trouble, as we've seen.

Thinking twice about singularity: The EventBus example

Hint: Are you sure there's a single instance? Really sure?

Are you aware of the EventBus project? (See a JavaOne 2006 session ).

Well it's a nice event bus. But it uses singletons:

public StatusBar() {
  EventBus.subscribe(StatusEvent.class, this);
}

Now, why a single event bus?

Imagine I'm building a text editor. With an event bus. With a singleton.

What about if I want to build another editor window? Will the two editor windows share the same event bus? If I fire a "FileOpenEvent" through the single bus, which of the two windows will react to the event? Both?

Conclusion: beware of singletons

Yes. Beware of singletons. There're lots of hidden working hours behind them! Use your singletons wisely. After all, singletons are evil

Happy recovery from singletonitis, ;-)

Antonio

blog comments powered by Disqus