Download (direct link):
Now that we've provided a review of the Singleton design pattern, let's discuss what could go wrong. The following sections discuss bad practices that we have commonly seen and provide suggestions on resolving the resulting dilemmas that occur.
When Multiple Singletons in Your VM Happen
Right now, you're thinking, "What? Isn't this contrary to the definition of a Singleton?" Yes, you're absolutely correct. However, if a Singleton class is not written correctly in a one-VM multithreaded system, problems can arise.
Consider a Singleton designed to use lazy instantiation, as implemented in Listing 15.2. If the getInstance() method is not synchronized, the following could happen: Two threads could call getInstance() simultaneously, and two different versions of FirstCall could be returned. Figure 15.1 shows a pictorial representation of how this could occur in one virtual machine. At time t=30, two threads in one virtual machine call FirstCall.getInstance(), and two different objects are returned. This could be extremely dangerous if, for example, the Singleton is supposed to guarantee a single point of access to an external resource. If the Singleton class is writing data to a file, for example, several problems could arise, ranging from corrupted data to unintended mutual exclusion problems.
Figure 15.1 The synchronization problem.
120 Item 15
Like most concurrency issues, this is a difficult problem to debug. The key point here is to make certain that your getInstance() method is synchronized when you are using the lazy instantiation Singleton strategy shown in Listing 15.2.
When Singletons are Used as Global Variables, or Become Non-Singletons
Sometimes the Singleton class is abused. One example that we've unfortunately seen quite a bit is when a Singleton class is used as a "global variable" to eliminate parameter passing. Using a Singleton in this manner is poor practice, and it may affect the flexibility of your project's software architecture. One example that we have seen is where a code author placed his main application's GUI object in a Singleton with synchronized setGUI() and getGUI() methods, to avoid passing the user interface component to other objects in the system. The strategy worked well, until the software customer requested multiple applications per VM. Because some of the classes got a handle to the application's user interface with the getGUI() method in the Singleton, this had to be rewritten.
We shudder to even show this next example, but an extreme case is shown in List-
01 public class GlobalVarSingleton
04 private static GlobalVarSingleton
05 m_instance = new GlobalVarSingleton();
07 //The use of this class is NOT recommended!
08 public int x = 0;
09 public int y = 1;
10 public int z = 2;
12 private void GlobalVarSingleton()
17 * point of entry to this class
19 public static synchronized GlobalVarSingleton getInstance(
21 return m_instance;
24 public static void main(String args)
26 //Bad usage example:
Listing 15.3 Singleton as global variable
Avoiding Singleton Pitfalls 121
28 GlobalVarSingleton globals =
30 globals.x = 333;
31 globals.y = 40803;
32 globals.z = 21;
35 At this point, the offender calls other classes
36 who call GlobalVarSingleton.getInstance() to get
37 (and change) values of x, y, and z.
Listing 15.3 (continued)
Listing 15.3 shows the poor choice of using a Singleton to hold variables. In lines 8, 9, and 10, there are public instance variables x, y, and z. The main() method of Listing 15.3 shows an example usage of this, where a class in the VM gets the Singleton, alters the variables, and calls another class, which gets the values of those variables and changes them. It goes without saying that there will be synchronization issues in this example, and it also goes without saying that this is poor design. Of course, many Singletons are not as blatant as this; some are designed correctly, but somewhere along the road, an unenlightened programmer could add things to it to accomplish ends like this. Please be aware that this is poor practice, and keep an eye on your existing Singleton classes.
Over time, a code base evolves. Software engineers modify classes, and every once in a while, we have seen times where Singletons, accidentally or intentionally, stop being Singletons. One of the most common events that we have seen is when a novice programmer changes the private constructor to a public one, leading to havoc throughout the baseline. Watch your baseline!
In conclusion, when you are deciding whether to create a Singleton class, first ask yourself the following questions:
¦¦ Does there need to be one global entry point to this class?
¦¦ Should there be only one instance to this class in the VM?
If your answer is yes, then use a Singleton. If no, don't use this design pattern.