Creating a Thread Safe Singleton Class with Examples
Ask any Java developer to name a design pattern that they have used at work and I guarantee you that one of their first choices will be the Singleton Design Pattern. This design pattern is used in cases where it is desirable to have one and only one instance of a class where other classes access the required functionality. It is one of the easiest design patterns to implement, yet it presents many pitfalls especially in a multithreaded environment where multiple threads may be trying to access the singleton class. Our goal in a multithreaded environment is to create a Thread Safe Singleton Class that creates an instance of a class if one has not yet been created, if one has been created then it should simply return an instance of the already created class. In this tutorial, “Creating a Thread Safe Singleton Class with Examples“, we will show you many examples of how to create a singleton class and discuss some of the pitfalls associated with each.
Advantages of a Singleton Class
- Ensures only one instance of class is created
- Provides a global single point of access
- One of the simplest design patterns to implement
In the following example, I will illustrate creating the default or classic example of a Java Singleton Class. I will point out a few details to help you understand the finer points in a ClassicSingleton. First, you will notice that I have created a private static Singleton variable called instance. Second, you will note that the constructor is made private so that outside so that it cannot be instantiated from the outside. Third, you will notice that in the getInstance method I check to see if instance is equal to null and if it is I will create an instance of ClassicSingleton with the new operator in Java. Otherwise, an instance must have been created already and I simply return that previous created instance to the caller.
Singleton Class Example (Single Threaded)
package com.avaldes.tutorials; public class ClassicSingleton{ private static ClassicSingleton instance= null; private ClassicSingleton() { } public static ClassicSingleton getInstance() { if (instance == null) { instance = new ClassicSingleton(); } return instance; } }
In the previous example, the following code is not thread-safe:
if (instance == null) { instance = new ClassicSingleton(); }
In this example, we risk the possibility of the code being interrupted after line 1 (if statement) and before line 2, calling new ClassicSingleton(). The possibility, albeit small exists that if another thread would get into same block scope it is possible for more than one Singleton instances to be created thus violating the singleton design pattern we have tried to create. This lazy loading example of a singleton class works fine in a single threaded environment, but in a multithreaded environment more needs to be done. Let’s see some more examples.
Pros/Cons
- Working Singleton for Single-Threaded Model
- Not Thread-Safe (cannot be used in concurrent environment)
Singleton Class Example (Lazy Initialization)
package com.avaldes.tutorials; public class LazyInitSingleton { private static LazyInitSingleton instance; private LazyInitSingleton() { } public synchronized static LazyInitSingleton getInstance() { if (instance == null) { instance = new LazyInitSingleton(); } return instance; } }
In this example, we synchronize the getInstance() method using the synchronized keyword. All threads that need to get access to the instance in the singleton class will go through this public synchronized method. The first time the call is made, the instance will be null and a new instance will be created using the new operator on the private constructor. After that, all subsequent calls will simply return the instance that was previously created. However, the problem with this example, is that every call is incurring the synchronization overhead and performance penalty because getInstance is synchronized. Even after the instance has been created, every call to getInstance incurs the performance hit. A better approach is needed…
Pros/Cons
- Synchronization works
- Thread Safe
- Lazy Initialization
- Slow Synchronization
- Wasteful synchronization after instance is created (not needed)
Singleton Class Example (Double-Checked Locking Idiom)
package com.avaldes.tutorials; public class DoubleCheckedSingleton { private static DoubleCheckedSingleton instance; private static Object lock = new Object(); private DoubleCheckedSingleton() { } // This is a broken multithreaded version // using the double-checked idiom public static DoubleCheckedSingleton getInstance() { if (instance == null) { synchronized (lock) { if (instance == null) { instance = new DoubleCheckedSingleton(); } } } return instance; } }
In Java versions 1.4 and earlier this mechanism appears to work fine as it is extremely difficult to distinguish between an correctly working implementation and one that may have some subtle problems. With incorrect implementations, the failures happen intermittently. Incorrect implementations of double-checked locking may make failures difficult to reproduce.
Pros/Cons
- Attempts to fix problem with synchronized method
- Lazy Initialization
- Broken synchronization
- Very subtle errors, difficult to distinguish from correct working version
- Reproduction of failures hard to pinpoint as they do not occur all the time
Singleton Class Example (Double-Checked Locking Idiom with Volatile)
package com.avaldes.tutorials; public class DoubleCheckedSingletonFixed { private volatile static DoubleCheckedSingletonFixed instance; private static Object lock = new Object(); private DoubleCheckedSingletonFixed() { } // This is a fixed multithreaded version // using the double-checked idiom // fixed for Java 1.5 and above public static DoubleCheckedSingletonFixed getInstance() { if (instance == null) { synchronized (lock) { if (instance == null) { instance = new DoubleCheckedSingletonFixed(); } } } return instance; } }
As of Java versions 1.5 and above, the problems with the previous implementation of fixed. This version uses volatile keyword which ensures that all threads see the same variable as soon as it is changed.
Pros/Cons
- Attempts to fix problem with synchronized method
- Works under JDK 1.5
- Lazy Initialization
- Broken under JDK 1.4 and lower because of volatile usage and semantics
Singleton Class Example (Pre-initialized Class Loading)
package com.avaldes.tutorials; public class PreInitializedSingleton { private static final PreInitializedSingleton instance = new PreInitializedSingleton(); private PreInitializedSingleton() {} public static PreInitializedSingleton getInstance() { return instance; } }
In this example, the static variable is created and initialized as soon as the class is loaded. It is thread-safe, however, this example’s main disadvantage is that it uses up memory and CPU resources prior to actually needing it. If the class is never uses than this may have been a waste of time and resources. Let’s look at a better approach.
Pros/Cons
- Thread-Safe as initialization is done during class loading
- No need for any synchronization
- Does not make use of Lazy Initialization
- May use up memory and CPU resources even if never used
Singleton Class Example (Initialization On-Demand Holder)
package com.avaldes.tutorials; public class InitializationOnDemandSingleton { // Inner class for correct implementation of lazy loading private static class Holder { private static final InitializationOnDemandSingleton instance = new InitializationOnDemandSingleton(); } private InitializationOnDemandSingleton() {} public static InitializationOnDemandSingleton getInstance() { return Holder.instance; } }
This example works well because it provides a thread-safe, fast and very efficient lazy loading initialization mechanism. This singleton example completes quickly because during the initialization there are no static variables to initialize early on. The static inner class Holder is not initialized by the JVM until it used in the getInstance() method. Once this happens the JVM will load and initialize the Holder class. This initialization is guaranteed to be sequential and non-concurrent by the Java Language Specification. This removes any need to add any type of synchronization over from our singleton class.
Pros/Cons
- Thread-Safe as initialization is done on-demand
- No need for any synchronization
- Lazy Initialization
- Uses static inner class to ensure on-demand loading
Singleton Class Example (Using enum)
package com.avaldes.tutorials; public enum EnumSingleton { INSTANCE; public void doSomething() { // do something specific to your class..... } }
In the book, “Effective Java“, Joshua Bloch suggests that this is best best approach to implement a singleton for any JVM that supports enums.
Pros/Cons
- Thread-Safe as JVM ensures only one instantiation of enum
- Enums are very easy to write
- No need for any synchronization
- No drawbacks with respect to serialization and reflection
- Enum is somewhat inflexible as superclass is always enum
- Enum contains some additional public methods which may muddy the waters…
Final Thoughts
There you have it. There are quite a few different approaches to creating a thread-safe singleton class each with some advantages and disadvantages. I still believe the best one for me is the Initialization On-Demand Singleton which performs the lazy loading and does not add the extra methods (valueOf, compareTo, values(), etc) found with enum class implementation.
Related Posts
- Java Thread, Concurrency and Multithreading Tutorial
This Java Thread tutorial will give you a basic overview on Java Threads and introduce the entire tutorial series on concurrency and multithreading. From here, you will learn about many java thread concepts like: Thread States, Thread Priority, Thread Join, and ThreadGroups. In addition, you will learn about using the volatile keyword and examples on using wait, notify and notifyAll. - Java Thread States - Life Cycle of Java Threads
Get a basic understanding of the various thread states. Using the state transition diagram we show the various states for a Java thread and the events that cause the thread to jump from one state to another. - Creating Java Threads Example
In this post we cover creating Java Threads using the two mechanisms provided in Java, that is, by extending the Thread class and by implementing Runnable interface for concurrent programming. - Java Thread Priority Example
In this post we cover Thread priorities in Java. By default, a java thread inherits the priority (implicit) of its parent thread. Using the setPriority() method you can increase or decrease the thread priority of any java thread. - Java ThreadGroup Example
Sometimes we will need to organize and group our threads into logical groupings to aid in thread management. By placing threads in a threadGroup all threads in that group can be assigned properties as a set, instead of going through the tedious task of assigning properties individually. - Java Thread Sleep Example
We seem to use this method very often to temporarily suspend the current threads execution for a specific period of time. Let's spend some time and familiarize ourselves with what this method actually does. - Java Thread Join Example
In Java, using Thread.join() causes the current thread to wait until the specified thread dies. Using this method allows us to impose an order such that we can make one thread wait until the other completes doing what it needed to do, such as completing a calculation. - Examining Volatile Keyword with Java Threads
When we declare a field as volatile, the JVM will guarantee visibility, atomicity and ordering of the variable. Without it the data may be cached locally in CPU cache and as a result changes to the variable by another thread may not be seen by all other threads resulting in inconsistent behaviour. - Java Threads Wait, Notify and NotifyAll Example
The purpose of using notify() and notifyAll() is to enable threads to communicate with one another via some object on which to performing the locking. A thread using the wait() method must own a lock on the object. Once wait() is called, the thread releases the lock, and waits for another thread to either call notify() or notifyAll() method. - Java Thread Deadlock Example and Thread Dump Analysis using VisualVM
Deadlock is a condition where several threads are blocking forever, waiting for the other to finish but they never do. This tutorial will discuss situations that will lead to Java Thread deadlock conditions and how they can be avoided. In addition, we will discuss using Java VisualVM to pinpoint and analyze the source of the deadlock conditions. - Java Thread Starvation and Livelock with Examples
Starvation occurs when a thread is continually denied access to resources and as a result it is unable to make progress. Thread liveLock is a condition that closely resembles deadlock in that several processes are blocking each other. But with livelock, a thread is unable to make any progress because every time it tries the operation always fails. - Java Synchronization and Thread Safety Tutorial with Examples
One of Java's many strengths come from the fact that it supports multithreading by default as has so from the very onset. One of the mechanisms that Java uses for this is via synchronization. When we use the synchronized keyword in Java we are trying limit the number of threads that can simultaneously access and modify a shared resource. The mechanism that is used in Java's synchronization is called a monitor. - Creating a Thread Safe Singleton Class with Examples
In this tutorial we cover many examples of creating thread-safe singleton classes and discuss some of the shortfalls of each and provide some recommendations on best approaches for a fast, efficient and highly concurrent solution. - Java Threads and Concurrent Locks with Examples
In this tutorial we will focus primarily on using the concurrent utilities and how these can make concurrent programming easier for us.
Leave a Reply