Join Elisabeth Robson for an in-depth discussion in this video Improving the singleton pattern implementation, part of Programming Foundations: Design Patterns.
We'll show you two ways to make the Singleton thread safe. The code for these two examples is in the packages, singleton stat, and Singleton threads safe in the example files. The first in Singleton state uses a static initializer to create the Singleton as soon as the class is loaded by the JVM. This is guaranteed to be thread safe. The JVM will create the instance before any thread accesses the static variable. As in the classic Singleton, we have a private constructor.
In the instance of the Singleton is kept in a private static variable. However, now we go ahead and assign an instance of the Singleton when we initialize the static variable. So the get instance method simply returns that instance. It no longer needs to create the instance of the Singleton. There's no change in how we use the Singleton. Just like before, we call the class method get instance. To get an instance of the Singleton. And then just call the other methods on the Singleton like normal.
This way of creating a Singleton is thread safe. So it is an improvement over the classic Singleton in situations when a program is using multiple threads. The downside of creating a Singleton like this, is that we're creating it eagerly rather than lazily. That is, the Singleton is always created. Even if it's never needed. Now, in many situations, that might be just fine. Because you may know that the Singleton will always be needed. But it's something to keep in mind in situations where the Singleton might not be needed, particularly if your Singleton class is complex and and creating instance of it may slow down the loading of your code by the JVM.
Another way we can ensure thread safety is to use the synchronized keyword on the getInstance method. In this example, we go back to creating the Singleton in the getInstance method but hasn't already been created, but we make sure that only one thread can access this method at a time. So there is no chance of creating multiple instances of this Singleton. In a multithreaded environment. We do this by adding the synchronized keyword to the getInstance method definition. This solution creates the Singleton lazily, like the classic Singleton does, so the object is created only if you really need it.
However, there is a downside to this solution. Synchronization is expensive. That is, synchronized code takes a lot longer to run than unsynchronized code. And because the get instance method is synchronized, every call to get instance will be more expensive, not just the first call. So how do you know which of these methods to use to create a Singleton? Well, it depends on your application. If your application doesn't need to worry about thread safety, then use classic Singleton. If you're worried about thread safety, and you know you'll always need the Singleton, then use the static initializer.
However if you want to take advantage of lazy instantiation and you're aren't too worried about the overhead of synchronization then synchronize your get instance method like we're doing here. The Singleton pattern is deceptively simple but now you have some options for how to create a singleton in different situations.
- What are design patterns?
- Encapsulating code that varies with the strategy pattern
- Setting behavior dynamically
- Implementing the observer pattern
- Creating chaos with inheritance
- Extending behavior with composition
- Dealing with multithreading and the singleton pattern
- Revising the design for a state machine
- Encapsulating iteration with the collection pattern
- Encapsulating object creation with the factory method pattern