http://www.developer.com/

Back to article

Threads Versus The Singleton Pattern


May 31, 2007

Given the recent uptake in the application of the singleton design pattern, it bears noting that certain applications of this pattern might not play nicely should they be utilized in a threaded program. That is to say, there are times when your design intent is that the "singleton" concept should be applied to a user or a transaction, and not simply to the application itself. You are rather likely to encounter this very situation if you write J2EE code because each request is typically processed from its own thread. Depending on how long some JDBC operations take for your application, you might inadvertently have a singleton helper class step on itself while dealing with two (or more) requests. Although you probably could address some of these issues with the judicious use of synchronized blocks, do not overlook the utility of the ThreadLocal class. In this article, I will demonstrate the risk of not accounting for Threads when using a singleton pattern and show how simple it is to address.

ThreadLocal Overview

The java.lang.ThreadLocal class has been present in the standard J2SE API since the 1.2 release, but it hasn't received much publicity in articles. (At least not quite as much as the singleton pattern has recently, in my opinion.) To quote from the API documentation:

"This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread."

In other words, whereas an ordinary "static" variable is shared across all instances of its class everywhere throughout the application, a "static ThreadLocal" is shared across all instance of its class only within the context of a particular thread. Because ThreadLocal itself is a type (specifically, a class) and not simply a modifier, you will initialize it an object that holds the value you otherwise would have created directly. (Make use of the primitive wrapper classes as needed.) I recommend reading the more official descriptions from the standard API, but to paraphrase, the methods are:

public Object initialValue() Functionally similar to a delayed constructor for your value object that is called the first time the get() method is called. Will return null unless you override.
public void set(Object) Setter method for the value object inside the ThreadLocal.
public Object get() Getter method for the value object inside the ThreadLocal.
public void remove() Removes the value object. If get() is called again, the initialValue() method is again triggered.

Also note that ThreadLocal itself has been "genericized." This article will show such utilization. (If you are a little weak on Java generics, this lesson, part of Sun's online Java tutorial, is a good place to start.)

Modification of a factory class that naively passes out references to a singleton to instead be thread-saavy is fairly simple. But first, you should set up a demonstration to illustrate the danger of not doing so.

Problem Demonstration

The Helper Class

First, you will define a class called Helper, whose job is to maintain some notion of state, and more specifically, the progression of changes to that state:

public class Helper {

   public static final int BEGINNING=0;
   public static final int MIDDLE=1;
   public static final int END=2;
   public static final int DONE=3;

   private int state = BEGINNING;

   public void setState(int newState) {
      state = newState;
   }

   public int getState() {
      return state;
   }

   public String toString() {
      return "Helper has state "+state;
   }
}

Usage Illustration

The usage pattern for this class is that some external section of code obtains a reference to a Helper object and, depending on the Helper's state, performs some conditional operation (and then updates the Helper's state). Note that, for the immediately following example, a singleton pattern is not yet employed. (You will get to that shortly.) This is also a fairly contrived example, and as such it sleeps (briefly) to simulate effects of long-running operations:

public class Demo1 {
   public static void main(String[] args) {
      Helper helper = new Helper();
      do {
         try {
            Thread.sleep((long)(250*Math.random()));
         } catch (InterruptedException e) {
            break;
         }
         switch (helper.getState()) {
         case Helper.BEGINNING:
            System.out.println(helper);
            System.out.println("Beginning operation finished.");
            helper.setState(Helper.MIDDLE);
            break;
         case Helper.MIDDLE:
            System.out.println(helper);
            System.out.println("Middle operation finished.");
            helper.setState(Helper.END);
            break;
         case Helper.END:
            System.out.println(helper);
            System.out.println("End operation finished.");
            helper.setState(Helper.DONE);
            break;
         }
      } while (helper.getState() != Helper.DONE);
      System.out.println("Code section finished.");
   }
}

The expectation is that the output you see on the screen is:

Helper has state 0
Beginning operation finished.
Helper has state 1
Middle operation finished.
Helper has state 2
End operation finished.
Code section finished.

... and when your code (or at least everything related to the existence and usage of the Helper object) is single-threaded, this works fine. But, for some reason (related to experience or design requirements), you drag a factory-with-singleton design into the picture.

The Simple Singleton Factory

Consider that you decide you do not want to instantiate multiple Helper objects—you only want one Helper object to exist. One reason for this decision is that you might have several methods in several classes that all need access to the same "state" information. That is, things are spread out farther than the simple (and admittedly contrived) do-while loop shown above. In that case, a common solution is the arrange for a factory class to provide, via a static getter method, just one instance of the Helper. Consider this simple HelperFactory class, whose job is to ensure that, when asked, it only hands out the same singular instance of a Helper class:

public class HelperFactory {
   private static Helper instance = new Helper();
   public static Helper getHelper() {
      return instance;
   }
}

The usage code above changes from Helper helper = new Helper(); to Helper helper = HelperFactory.getHelper();. Now, for that demonstrational code block, little is gained. But in a real application where, as I mentioned, your working code is spread far and wide, yet tied to the same progression of state, each interested piece of code can directly access this common, application-static Helper object via this factory getter method. (The alternative is fairly cumbersome: pass the same Helper object around in all your method calls. Enjoy the additional maintenance headaches for doing so while you're at it!) Because my assumption for this article is that you are familiar with this pattern, I won't dwell on it further.

Threaded Headaches

Now, amend your usage code somewhat to reside in the "run()" method of a Thread-derived class. Note that you also will change the println statements slightly to display the name of the thread so you can more clearly identify which thread is emitting which message. More importantly, you access a singleton Helper object via the simple factory shown above:

public class Runner extends Thread {
   public Runner(String name) {
      super(name);
   }
   public void run() {
      Helper helper = HelperFactory.getHelper();
      do {
         try {
            Thread.sleep((long)(250*Math.random()));
         } catch (InterruptedException e) {
            break;
         }
         switch (helper.getState()) {
         case Helper.BEGINNING:
            System.out.println(getName()+": "+helper);
            System.out.println(getName()+
               ": Beginning operation finished.");
            helper.setState(Helper.MIDDLE);
            break;
         case Helper.MIDDLE:
            System.out.println(getName()+": "+helper);
            System.out.println(getName()+
               ": Middle operation finished.");
            helper.setState(Helper.END);
            break;
         case Helper.END:
            System.out.println(getName()+": "+helper);
            System.out.println(getName()+
               ": End operation finished.");
            helper.setState(Helper.DONE);
            break;
         }
      } while (helper.getState() != Helper.DONE);
      System.out.println("Code section finished.");
   }
}

...and then modify the main method to create a couple Threads of this class to start them:

public class Demo2 {
   public static void main(String[] args) {
      Thread t1 = new Runner("threadA");
      t1.start();
      Thread t2 = new Runner("threadB");
      t2.start();
   }
}

Run this several times and compare the output for each run. Here's a sample when I did:

threadB: Helper has state 0
threadB: Beginning operation finished.
threadA: Helper has state 1
threadA: Middle operation finished.
threadB: Helper has state 2
threadB: End operation finished.
Code section finished.
Code section finished.

----------------

threadB: Helper has state 0
threadB: Beginning operation finished.
threadA: Helper has state 1
threadA: Middle operation finished.
threadA: Helper has state 2
threadA: End operation finished.
Code section finished.
Code section finished.

----------------

threadB: Helper has state 0
threadB: Beginning operation finished.
threadB: Helper has state 1
threadB: Middle operation finished.
threadA: Helper has state 2
threadA: End operation finished.
Code section finished.
Code section finished.

All output sections are different, and given the random variation of the sleep timer, this is somewhat expected. More importantly, all three are wrong—in none of them does any one thread print messages for all three helper states. (Although for different purposes you might desire the effect shown, it is wrong for the purposes of this article.) This is, at last, a visual illustration of how the two threads compete with each other for the state of the same singleton Helper object. The failure point, and the solution, lie in the factory class itself.

Problem Resolution: The Updated ThreadLocal Singleton Factory

Instead of storing a "static Helper" instance variable in the factory class, instead store a "static ThreadLocal" instance variable in the factory class, and arrange (via override) to return a Helper object from its get() method:
public class HelperFactory {

   private static ThreadLocal instance = new ThreadLocal() {
      protected Helper initialValue() {
         return new Helper();
      }
   };

   public static Helper getHelper() {
      return instance.get();
   }
}

That is everything you need: declaration of a static ThreadLocal object with an override of its initialValue() method. Note also how the static factory getter method now delegates to the ThreadLocal object's get() method. Run the demo code a few more times. Although the exact statement order will still be somewhat mixed, both threads will accomplish their respective objects successfully:

threadB: Helper has state 0
threadB: Beginning operation finished.
threadA: Helper has state 0
threadA: Beginning operation finished.
threadB: Helper has state 1
threadB: Middle operation finished.
threadA: Helper has state 1
threadA: Middle operation finished.
threadB: Helper has state 2
threadB: End operation finished.
Code section finished.
threadA: Helper has state 2
threadA: End operation finished.
Code section finished.

Conclusion

To wrap up, you can, with the slightest amount of work, be more forward-thinking in the design of your singleton factory classes. You might not be working on a multi-threaded application now, but a quick turn of the fate of your use cases or requirements might force it into existence later—long after you've forgotten about the operational details in the factory class. Relatedly, it is easy to get so involved in the details and business logic of JDBC code for a J2EE web application that you forget how each request is likely processed by a separate thread. (This could turn into an interestingly stressful debug session, as it'll more likely bite customers on site than developers in house.) A common pattern is to create some sort of helper object to do a lot of the common-place heavy lifting associated with JDBC calls. Other similar situations might arise in a multi-threaded network service utility. The ThreadLocal-based solution is a simple and effective solution that you should definitely keep in your mental toolbox.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date