The Singleton pattern is deceptively simple, even and especially for Java developers. In this classic JavaWorld article, David Geary demonstrates how Java developers implement singletons, with code examples for multithreading, classloaders, and serialization using the Singleton pattern. He concludes with a look at implementing singleton registries in order to specify singletons at runtime.
Sometimes it's appropriate to have exactly one instance of a class: window managers, print spoolers, and filesystems are prototypical examples. Typically, those types of objects—known as singletons—are accessed by disparate objects throughout a software system, and therefore require a global point of access. Of course, just when you're certain you will never need more than one instance, it's a good bet you'll change your mind.
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
- Ensure that only one instance of a class is created
- Provide a global point of access to the object
- Allow multiple instances in the future without affecting a singleton class's clients
Although the Singleton design pattern—as evidenced below by the figure below—is one of the simplest design patterns, it presents a number of pitfalls for the unwary Java developer. This article discusses the Singleton design pattern and addresses those pitfalls.
More about Java design patterns
You can read all of David Geary's Java Design Patterns columns, or view a listing of JavaWorld's most recent articles about Java design patterns. See "" for a discussion about the pros and cons of using the Gang of Four patterns. Want more? Get the delivered to your inbox.
The Singleton pattern
In Design Patterns: Elements of Reusable Object-Oriented Software, the Gang of Four describe the Singleton pattern like this:
Ensure a class has only one instance, and provide a global point of access to it.
The figure below illustrates the Singleton design pattern class diagram.
As you can see, there's not a whole lot to the Singleton design pattern. Singletons maintain a static reference to the sole singleton instance and return a reference to that instance from a static instance()
method.
Example 1 shows a classic Singleton design pattern implementation:
Example 1. The classic singleton
public class ClassicSingleton {
private static ClassicSingleton instance = null;
protected ClassicSingleton() {
// Exists only to defeat instantiation.
}
public static ClassicSingleton getInstance() {
if(instance == null) {
instance = new ClassicSingleton();
}
return instance;
}
}
The singleton implemented in Example 1 is easy to understand. The ClassicSingleton
class maintains a static reference to the lone singleton instance and returns that reference from the static getInstance()
method.
There are several interesting points concerning the ClassicSingleton
class. First, ClassicSingleton
employs a technique known as lazy instantiation to create the singleton; as a result, the singleton instance is not created until the getInstance()
method is called for the first time. This technique ensures that singleton instances are created only when needed.
Second, notice that ClassicSingleton
implements a protected constructor so clients cannot instantiate ClassicSingleton
instances; however, you may be surprised to discover that the following code is perfectly legal:
public class SingletonInstantiator {
public SingletonInstantiator() {
ClassicSingleton instance = ClassicSingleton.getInstance();
ClassicSingleton anotherInstance =
new ClassicSingleton();
...
}
}
How can the class in the preceding code fragment—which does not extend ClassicSingleton
—create a ClassicSingleton
instance if the ClassicSingleton
constructor is protected? The answer is that protected constructors can be called by subclasses and by other classes in the same package. Because ClassicSingleton
and SingletonInstantiator
are in the same package (the default package), SingletonInstantiator()
methods can create ClassicSingleton
instances. This dilemma has two solutions: You can make the ClassicSingleton
constructor private so that only ClassicSingleton()
methods call it; however, that means ClassicSingleton
cannot be subclassed. Sometimes, that is a desirable solution; if so, it's a good idea to declare your singleton class final
, which makes that intention explicit and allows the compiler to apply performance optimizations. The other solution is to put your singleton class in an explicit package, so classes in other packages (including the default package) cannot instantiate singleton instances.
A third interesting point about ClassicSingleton
: it's possible to have multiple singleton instances if classes loaded by different classloaders access a singleton. That scenario is not so far-fetched; for example, some servlet containers use distinct classloaders for each servlet, so if two servlets access a singleton, they will each have their own instance.
Fourth, if ClassicSingleton
implements the java.io.Serializable
interface, the class's instances can be serialized and deserialized. However, if you serialize a singleton object and subsequently deserialize that object more than once, you will have multiple singleton instances.
Finally, and perhaps most important, Example 1's ClassicSingleton
class is not thread-safe. If two threads—we'll call them Thread 1 and Thread 2—call ClassicSingleton.getInstance()
at the same time, two ClassicSingleton
instances can be created if Thread 1 is preempted just after it enters the if
block and control is subsequently given to Thread 2.
As you can see from the preceding discussion, although the Singleton pattern is one of the simplest design patterns, implementing it in Java is anything but simple. The rest of this article addresses Java-specific considerations for the Singleton pattern, but first let's take a short detour to see how you can test your singleton classes.
Test singletons
Throughout the rest of this article, I use JUnit in concert with log4j to test singleton classes. If you are not familiar with JUnit or log4j, see Resources.
Example 2 lists a JUnit test case that tests Example 1's singleton:
Example 2. A singleton test case
import org.apache.log4j.Logger;
import junit.framework.Assert;
import junit.framework.TestCase;
public class SingletonTest extends TestCase {
private ClassicSingleton sone = null, stwo = null;
private static Logger logger = Logger.getRootLogger();
public SingletonTest(String name) {
super(name);
}
public void setUp() {
logger.info("getting singleton...");
sone = ClassicSingleton.getInstance();
logger.info("...got singleton: " + sone);
logger.info("getting singleton...");
stwo = ClassicSingleton.getInstance();
logger.info("...got singleton: " + stwo);
}
public void testUnique() {
logger.info("checking singletons for equality");
Assert.assertEquals(true, sone == stwo);
}
}
Example 2's test case invokes ClassicSingleton.getInstance()
twice and stores the returned references in member variables. The testUnique()
method checks to see that the references are identical. Example 3 shows that test case output:
Example 3. Test case output
Buildfile: build.xml
init:
[echo] Build 20030414 (14-04-2003 03:08)
compile:
run-test-text:
[java] .INFO main: getting singleton...
[java] INFO main: created singleton: Singleton@e86f41
[java] INFO main: ...got singleton: Singleton@e86f41
[java] INFO main: getting singleton...
[java] INFO main: ...got singleton: Singleton@e86f41
[java] INFO main: checking singletons for equality
[java] Time: 0.032
[java] OK (1 test)
As the preceding listing illustrates, Example 2's simple test passes with flying colors—the two singleton references obtained with ClassicSingleton.getInstance()
are indeed identical; however, those references were obtained in a single thread. The next section stress-tests our singleton class with multiple threads.
Multithreading considerations
Example 1's ClassicSingleton.getInstance()
method is not thread-safe because of the following code:
1: if(instance == null) {
2: instance = new Singleton();
3: }
If a thread is preempted at Line 2 before the assignment is made, the instance
member variable will still be null
, and another thread can subsequently enter the if
block. In that case, two distinct singleton instances will be created. Unfortunately, that scenario rarely occurs and is therefore difficult to produce during testing. To illustrate this thread Russian roulette, I've forced the issue by reimplementing Example 1's class. Example 4 shows the revised singleton class:
Example 4. Stack the deck
import org.apache.log4j.Logger;
public class Singleton {
private static Singleton singleton = null;
private static Logger logger = Logger.getRootLogger();
private static boolean firstThread = true;
protected Singleton() {
// Exists only to defeat instantiation.
}
public static Singleton getInstance() {
if(singleton == null) {
simulateRandomActivity();
singleton = new Singleton();
}
logger.info("created singleton: " + singleton);
return singleton;
}
private static void simulateRandomActivity() {
try {
if(firstThread) {
firstThread = false;
logger.info("sleeping...");
// This nap should give the second thread enough time
// to get by the first thread.
Thread.currentThread().sleep(50);
}
}
catch(InterruptedException ex) {
logger.warn("Sleep interrupted");
}
}
}
Example 4's singleton resembles Example 1's class, except the singleton in the preceding listing stacks the deck to force a multithreading error. The first time the getInstance()
method is called, the thread that invoked the method sleeps for 50 milliseconds, which gives another thread time to call getInstance()
and create a new singleton instance. When the sleeping thread awakes, it also creates a new singleton instance, and we have two singleton instances. Although Example 4's class is contrived, it stimulates the real-world situation where the first thread that calls getInstance()
gets preempted.
Example 5 tests Example 4's singleton:
Example 5. A test that fails
import org.apache.log4j.Logger;
import junit.framework.Assert;
import junit.framework.TestCase;
public class SingletonTest extends TestCase {
private static Logger logger = Logger.getRootLogger();
private static Singleton singleton = null;
public SingletonTest(String name) {
super(name);
}
public void setUp() {
singleton = null;
}
public void testUnique() throws InterruptedException {
// Both threads call Singleton.getInstance().
Thread threadOne = new Thread(new SingletonTestRunnable()),
threadTwo = new Thread(new SingletonTestRunnable());
threadOne.start();
threadTwo.start();
threadOne.join();
threadTwo.join();
}
private static class SingletonTestRunnable implements Runnable {
public void run() {
// Get a reference to the singleton.
Singleton s = Singleton.getInstance();
// Protect singleton member variable from
// multithreaded access.
synchronized(SingletonTest.class) {
if(singleton == null) // If local reference is null...
singleton = s; // ...set it to the singleton
}
// Local reference must be equal to the one and
// only instance of Singleton; otherwise, we have two
// Singleton instances.
Assert.assertEquals(true, s == singleton);
}
}
}
Example 5's test case creates two threads, starts each one, and waits for them to finish. The test case maintains a static reference to a singleton instance, and each thread calls Singleton.getInstance()
. If the static member variable has not been set, the first thread sets it to the singleton obtained with the call to getInstance()
, and the static member variable is compared to the local variable for equality.
Here's what happens when the test case runs: The first thread calls getInstance()
, enters the if
block, and sleeps. Subsequently, the second thread also calls getInstance()
and creates a singleton instance. The second thread then sets the static member variable to the instance it created. The second thread checks the static member variable and the local copy for equality, and the test passes. When the first thread awakes, it also creates a singleton instance, but that thread does not set the static member variable (because the second thread has already set it), so the static variable and the local variable are out of synch, and the test for equality fails. Example 6 lists Example 5's test case output: